home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #11 / Amiga Plus CD - 2004 - No. 11.iso / AmiSoft / Game / misc / WormWars.lha / WormWars / Source / system.c < prev    next >
C/C++ Source or Header  |  2004-08-22  |  120KB  |  3,229 lines

  1. // 1.  INCLUDES -----------------------------------------------------------
  2.  
  3. #include <proto/asl.h>
  4. #include <proto/exec.h>
  5. #include <proto/diskfont.h>
  6. #include <proto/dos.h>
  7. #include <proto/gadtools.h>
  8. #include <proto/graphics.h>
  9. #include <proto/icon.h>
  10. #include <proto/intuition.h>
  11. #include <proto/lowlevel.h>
  12. #include <proto/timer.h>
  13. #include <clib/alib_protos.h>
  14.  
  15. #ifdef __STORM__
  16.     #include <proto/utility.h>
  17. #endif
  18. #ifdef LATTICE
  19.     #include <clib/utility_protos.h>
  20. #endif
  21.  
  22. #include <devices/audio.h>
  23. #include <devices/gameport.h>
  24. #include <exec/alerts.h>
  25. #include <exec/execbase.h>
  26. #include <graphics/gfxbase.h>
  27. #include <hardware/cia.h>
  28.  
  29. #include "diff.h"
  30. #include "same.h"
  31. #include "amiga.h"
  32. #include "libproto.h"
  33.  
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <assert.h>
  37.  
  38. // 2. DEFINES ------------------------------------------------------------
  39.  
  40. typedef LONG Fixed;          /* A fixed-point value, 16 bits to the left
  41.                                 of the point and 16 to the right. A Fixed
  42.                                 is a number of 2**16ths, ie. 65536ths. */
  43. typedef struct
  44. {   ULONG oneShotHiSamples,  /* # samples in the high octave 1-shot part */
  45.           repeatHiSamples,   /* # samples in the high octave repeat part */
  46.           samplesPerHiCycle; /* # samples/cycle in high octave, else 0 */
  47.     UWORD samplesPerSec;     /* data sampling rate */
  48.     UBYTE ctOctave,          /* # of octaves of waveforms */
  49.           sCompression;      /* data compression technique used */
  50.     Fixed volume;            /* playback nominal volume from 0 to Unity
  51.                                 (full volume). Map this value into the
  52.                                 output hardware's dynamic range (0-64). */
  53. } Voice8Header;
  54.  
  55. #define PATIENCE     50 // in INTUITICKs
  56. #define CONFIGLENGTH 23
  57.  
  58. #define ONE_BILLION  1000000000
  59.  
  60. /* joysticks */
  61.  
  62. #define JOYUP          1
  63. #define JOYDOWN        2
  64. #define JOYLEFT        4
  65. #define JOYRIGHT       8
  66. #define JOYFIRE1      16
  67. #define JOYFIRE2      32
  68. #define POTGOR         *(UWORD *)0xDFF016
  69.  
  70. #define OLD            1
  71. #define NEW            0
  72.  
  73. /* Help|About... window */
  74.  
  75. #define ABOUTLINES     6
  76. #define ABOUTSHADOW    DARKGREY
  77. #define ABOUTSHINE     LIGHTGREY
  78. #define PROJECTX     128
  79. #define PROJECTY      75
  80. #define KICKSTARTX   104
  81. #define KICKSTARTY    91
  82. #define WORKBENCHX   104
  83. #define WORKBENCHY    99
  84.  
  85. /* fxable/musicable */
  86.  
  87. #define FAILED         0 // tried and failed
  88. #define SUCCEEDED      1 // tried and succeeded
  89. #define UNTRIED        2 // untried, will try at startup
  90. #define DEFER          3 // untried, will try when needed
  91.  
  92. /* miscellaneous */
  93.  
  94. #define ANIMDELAY        1800
  95. #define ENTIREXPIXEL      640
  96. #define ENTIREYPIXEL      512
  97. #define MAXXSIZE         1280
  98. #define MAXYSIZE         1024
  99. #define FIELDCENTREXPIXEL  (STARTXPIXEL + ((ENDXPIXEL - STARTXPIXEL) / 2))
  100. #define FIELDCENTREYPIXEL  (STARTYPIXEL + ((ENDYPIXEL - STARTYPIXEL) / 2))
  101.  
  102. /* constant strings used more than once */
  103.  
  104. #define PATTERN            "(#?.lset)"
  105. #define OLDKICKSTART       "Worm Wars: You need Kickstart R2.04+!\n(Can't open intuition.library V37+!)\n"
  106.  
  107. #define ID_8SVX            MAKE_ID('8','S','V','X')
  108. #define ID_BODY            MAKE_ID('B','O','D','Y')
  109. #define ID_VHDR            MAKE_ID('V','H','D','R')
  110. #define PALCLOCK      3546895
  111. #define NTSCCLOCK     3579545
  112. #define SOFT               32
  113. #define LOUD               64 /* = Unity */
  114.  
  115. #define RUNDOWNX           (FIELDCENTREXPIXEL - 152)
  116. #define RUNDOWNX_1ST       32
  117. #define RUNDOWNX_2ND       (32 + (FONTX * 14))
  118. #define RUNDOWNX_3RD       (32 + (FONTX * 21))
  119. #define RUNDOWNX_4TH       (32 + (FONTX * 28))
  120. #define RUNDOWNY           (FIELDCENTREYPIXEL - 32)
  121. #define RUNDOWNY_2ND       12
  122. #define RUNSTRINGLENGTH    27
  123.  
  124. #define INDEX_ANIMATIONS      21
  125. #define INDEX_CREATEICONS     22
  126. #define INDEX_ENGRAVEDSQUARES 23
  127. #define INDEX_SHOWTITLEBAR    24
  128.  
  129. // 3. EXPORTED VARIABLES -------------------------------------------------
  130.  
  131. EXPORT struct Window            *HelpWindowPtr = NULL,
  132.                                 *MainWindowPtr = NULL;
  133. EXPORT ULONG                     DisplayWidth  = ENTIREXPIXEL,
  134.                                  DisplayHeight = ENTIREYPIXEL;
  135. EXPORT struct Menu*              MenuPtr       = NULL;
  136. EXPORT struct VisualInfo*        VisualInfoPtr = NULL;
  137. EXPORT struct timerequest*       TimerRqPtr    = NULL;
  138. EXPORT struct Screen*            ScreenPtr     = NULL;
  139. EXPORT ABOOL                     icons         = TRUE,
  140.                                  titlebar      = TRUE;
  141. EXPORT struct Library*           LowLevelBase  = NULL;
  142. EXPORT struct Device*            TimerBase     = NULL;
  143. EXPORT struct UtilityBase*       UtilityBase   = NULL;
  144.  
  145. // 4. IMPORTED VARIABLES -------------------------------------------------
  146.  
  147. IMPORT struct ExecBase*          SysBase;
  148.  
  149. IMPORT ABOOL                     anims,
  150.                                  engraved,
  151.                                  modified,
  152.                                  randomflag,
  153.                                  turbo;
  154. IMPORT TEXT                      pathname[81],
  155.                                  date[DATELENGTH + 1],
  156.                                  times[TIMELENGTH + 1],
  157.                                  stattext[7 + 1];
  158. IMPORT UBYTE                     board[MAXLEVELS + 1][MINFIELDX + 1][MINFIELDY + 1],
  159.                                  field[MAXFIELDX + 1][MAXFIELDY + 1],
  160.                                  missileframes[4][MISSILEFRAMES + 1],
  161.                                  birdframes[BIRDFRAMES + 1];
  162. IMPORT SBYTE                     a, level, levels, players, sourcelevel,
  163.                                  startx[MAXLEVELS + 1], starty[MAXLEVELS + 1];
  164. IMPORT UWORD                     ImageData[ARRAYSIZE + 1][SQUAREY * DEPTH4];
  165. IMPORT SWORD                     secondsleft, secondsperlevel,
  166.                                  fieldx, fieldy;
  167. IMPORT ULONG                     delay, r,
  168.                                  quantity[5][3];
  169. IMPORT struct HiScoreStruct      hiscore[HISCORES + 1];
  170. IMPORT struct WormStruct         worm[4];
  171. IMPORT struct CreatureInfoStruct creatureinfo[SPECIES + 1];
  172. IMPORT struct Image              Image;
  173.  
  174. // 5. MODULE VARIABLES ---------------------------------------------------
  175.  
  176. MODULE  ABOOL  clockdrawn   = FALSE,
  177.                eversent[4],
  178.                evertimed    = FALSE,
  179.                first        = TRUE,
  180.                ignore       = FALSE,
  181.                quiet        = FALSE,
  182.                saveconfig   = FALSE;
  183. MODULE  SBYTE  AudioClosed  = TRUE,
  184.                OldPri       = 0,
  185.                TimerClosed  = TRUE;
  186. MODULE  UBYTE  fxable       = UNTRIED,
  187.                mode         = NULL,
  188.                musicable    = UNTRIED;
  189. MODULE  ULONG  fsize,
  190.                millielapsed,
  191.                receipter[4] = {(ULONG) -1, (ULONG) -1, (ULONG) -1, (ULONG) -1};
  192. MODULE  UBYTE* fbase        = NULL;
  193. MODULE  BPTR   FilePtr      = NULL;
  194. MODULE  APTR   OldWindowPtr = NULL;
  195. MODULE  SBYTE  hiframe      = -1;
  196. MODULE  UBYTE                 ConfigBuffer[CONFIGLENGTH],
  197.                               song          = 0;
  198. MODULE  UWORD                 DisplayDepth  = DEPTH5;
  199. MODULE  ULONG                 DisplayID     = HIRES_KEY | PAL_MONITOR_ID | LACE;
  200.  
  201. MODULE struct Gadget         *CycleGadgetPtr[4]  = {NULL, NULL, NULL, NULL},
  202.                              *GListPtr           = NULL,
  203.                              *PrevGadgetPtr      = NULL,
  204.                              *ShuffleGadgetPtr   = NULL,
  205.                              *StringGadgetPtr[5] = {NULL, NULL, NULL, NULL, NULL};
  206. MODULE struct MsgPort        *AudioPortPtr[4]    = {NULL, NULL, NULL, NULL},
  207.                              *TimerPortPtr       = NULL;
  208. MODULE struct timeval        *TimeValPtr         = NULL;
  209.  
  210. MODULE struct CIA*           CIAPtr              = (struct CIA *) 0xBFE001;
  211. MODULE struct RDArgs*        ArgsPtr             = NULL;
  212. MODULE struct FileRequester* ASLRqPtr            = NULL;
  213. MODULE struct IOAudio*       AudioRqPtr[4]       = {NULL, NULL, NULL, NULL};
  214. MODULE struct TextFont*      FontPtr             = NULL;
  215. MODULE struct Process*       ProcessPtr          = NULL;
  216. MODULE struct MMD0*          SongPtr[7]          = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  217. MODULE struct WBArg*         WBArg               = NULL;
  218. MODULE struct WBStartup*     WBMsg               = NULL;
  219.  
  220. MODULE struct Library       *ASLBase             = NULL,
  221.                             *DiskFontBase        = NULL,
  222.                             *MEDPlayerBase       = NULL;
  223.  
  224. // 6. MODULE STRUCTURES --------------------------------------------------
  225.  
  226. MODULE struct NewGadget StringGadget =
  227. {   0, 0,
  228.     179, 12,
  229.     NULL,
  230.     NULL,
  231.     NULL,
  232.     NULL,
  233.     NULL,
  234.     NULL
  235. }, ShuffleGadget =
  236. {   0, 0,
  237.     0, 0,
  238.     NULL,
  239.     NULL,
  240.     NULL,
  241.     NULL,
  242.     NULL
  243. }, CycleGadget =
  244. {   0, 0,
  245.     128, 13,
  246.     NULL,
  247.     NULL,
  248.     NULL,
  249.     NULL,
  250.     NULL,
  251.     NULL
  252. };
  253.  
  254. MODULE struct
  255. {   STRPTR filename;
  256.     BYTE   volume;
  257.     ULONG  length[2], size, speed, bank;
  258.     UBYTE* base;
  259. } samp[SAMPLES + 1] =
  260. {   {      "PROGDIR:fx/dog.8svx", SOFT}, /* FXBORN_DOG */
  261.     {     "PROGDIR:fx/rain.8svx", SOFT}, /* FXBORN_RAIN */
  262.     {"PROGDIR:fx/lightning.8svx", LOUD}, /* FXGET_LIGHTNING */
  263.     {  "PROGDIR:fx/missile.8svx", LOUD}, /* FXBORN_MISSILE */
  264.     {  "PROGDIR:fx/protect.8svx", SOFT}, /* FXBORN_PROTECTOR */
  265.     {    "PROGDIR:fx/death.8svx", LOUD}, /* FXDEATH_WORM */
  266.     {  "PROGDIR:fx/enclose.8svx", LOUD}, /* FXDO_ENCLOSE */
  267.     { "PROGDIR:fx/fragment.8svx", SOFT}, /* FXBORN_FRAGMENT */
  268.     {     "PROGDIR:fx/ammo.8svx", LOUD}, /* FXGET_AMMO */
  269.     {  "PROGDIR:fx/cyclone.8svx", LOUD}, /* FXGET_CYCLONE */
  270.     {       "PROGDIR:fx/fx.8svx", SOFT}, /* FXGET_RAIN */
  271.     {   "PROGDIR:fx/grower.8svx", SOFT}, /* FXGET_GROWER */
  272.     {   "PROGDIR:fx/object.8svx", SOFT}, /* FXGET_OBJECT */
  273.     {  "PROGDIR:fx/powerup.8svx", LOUD}, /* FXGET_POWERUP */
  274.     {    "PROGDIR:fx/grave.8svx", SOFT}, /* FXGET_GRAVE */
  275.     {   "PROGDIR:fx/amigan.8svx", SOFT}, /* FXHELP */
  276.     {    "PROGDIR:fx/shoot.8svx", SOFT}, /* FXUSE_AMMO */
  277.     {   "PROGDIR:fx/armour.8svx", SOFT}, /* FXUSE_ARMOUR */
  278.     {     "PROGDIR:fx/bomb.8svx", LOUD}, /* FXUSE_BOMB */
  279.     { "PROGDIR:fx/teleport.8svx", SOFT}, /* FXUSE_TELEPORT */
  280.     {     "PROGDIR:fx/bird.8svx", SOFT}, /* FXBORN_BIRD */
  281.     {    "PROGDIR:fx/green.8svx", SOFT}, /* FXPAIN */
  282.     {      "PROGDIR:fx/red.8svx", SOFT},
  283.     {     "PROGDIR:fx/blue.8svx", SOFT},
  284.     {   "PROGDIR:fx/yellow.8svx", SOFT},
  285.     { "PROGDIR:fx/applause.8svx", SOFT}, /* FXAPPLAUSE (after each new hiscore) */
  286.     { "PROGDIR:fx/gameover.8svx", LOUD}, /* FXGAMEOVER (if all worms are dead) */
  287.     {    "PROGDIR:fx/click.8svx", SOFT}, /* FXCLICK (rundown, keypresses) */
  288.     {     "PROGDIR:fx/riff.8svx", LOUD}, /* FXRIFF (after each rundown) */
  289.     {    "PROGDIR:fx/siren.8svx", SOFT}, /* FXSIREN (out of time) */
  290.     {     "PROGDIR:fx/ding.8svx", SOFT}  /* FXDING */
  291. };
  292.  
  293. MODULE struct NewMenu NewMenu[] =
  294. {   { NM_TITLE, "Project",           0 , 0,                    0, 0}, //  0
  295.     {  NM_ITEM, "New",              "N", 0,                    0, 0}, //  1
  296.     {  NM_ITEM, "Open...",          "O", 0,                    0, 0}, //  2
  297.     {  NM_ITEM, "Revert",           "R", 0,                    0, 0}, //  3
  298.     {  NM_ITEM, NM_BARLABEL,         0 , 0,                    0, 0}, //  4
  299.     {  NM_ITEM, "Save",             "S", 0,                    0, 0}, //  5
  300.     {  NM_ITEM, "Save As...",       "A", 0,                    0, 0}, //  6
  301.     {  NM_ITEM, NM_BARLABEL,         0 , 0,                    0, 0}, //  7
  302.     {  NM_ITEM, "Delete...",        "D", 0,                    0, 0}, //  8
  303.     {  NM_ITEM, NM_BARLABEL,         0 , 0,                    0, 0}, //  9
  304.     {  NM_ITEM, "Quit",             "Q", 0,                    0, 0}, // 10
  305.     { NM_TITLE, "Edit",              0 , NM_MENUDISABLED,      0, 0}, // 11
  306.     {  NM_ITEM, "Cut",              "X", 0,                    0, 0}, // 12
  307.     {  NM_ITEM, "Copy",             "C", 0,                    0, 0}, // 13
  308.     {  NM_ITEM, "Paste",            "V", 0,                    0, 0}, // 14
  309.     {  NM_ITEM, NM_BARLABEL,         0 , 0,                    0, 0}, // 15
  310.     {  NM_ITEM, "Erase",            "E", 0,                    0, 0}, // 16
  311.     {  NM_ITEM, "Delete",            0 , 0,                    0, 0}, // 17
  312.     {  NM_ITEM, "Insert",            0 , 0,                    0, 0}, // 18
  313.     {  NM_ITEM, "Append",            0 , 0,                    0, 0}, // 19
  314.     { NM_TITLE, "Settings",          0 , 0,                    0, 0}, // 20
  315.     {  NM_ITEM, "Animations?",      "T", CHECKIT | MENUTOGGLE, 0, 0}, // 21
  316.     {  NM_ITEM, "Create Icons?",    "I", CHECKIT | MENUTOGGLE, 0, 0}, // 22
  317.     {  NM_ITEM, "Engraved Squares?", 0 , CHECKIT | MENUTOGGLE, 0, 0}, // 23
  318.     {  NM_ITEM, "Show Titlebar?",   "B", CHECKIT | MENUTOGGLE, 0, 0}, // 24
  319.     { NM_TITLE, "Help",              0 , 0,                    0, 0}, // 25
  320.     {  NM_ITEM, "Creatures...",     "1", 0,                    0, 0}, // 26
  321.     {  NM_ITEM, "Objects...",       "2", 0,                    0, 0}, // 27
  322.     {  NM_ITEM, NM_BARLABEL,         0 , 0,                    0, 0}, // 28
  323.     {  NM_ITEM, "About...",         "?", 0,                    0, 0}, // 29
  324.     {   NM_END, NULL,                0 , 0,                    0, 0}  // 30
  325. };
  326.  
  327. MODULE STRPTR CycleOptions[4][6] =
  328. { { "None",
  329.     "Amiga",
  330.     "Joystick 3",
  331.     "Gamepad 3",
  332.     "Lt. Kybd",
  333.     NULL
  334.   },
  335.   { "None",
  336.     "Amiga",
  337.     "Joystick 4",
  338.     "Gamepad 4",
  339.     "Rt. Kybd",
  340.     NULL
  341.   },
  342.   { "None",
  343.     "Amiga",
  344.     "Joystick 2",
  345.     "Gamepad 2",
  346.     NULL,
  347.     NULL
  348.   },
  349.   { "None",
  350.     "Amiga",
  351.     "Joystick 1",
  352.     "Gamepad 1",
  353.     NULL,
  354.     NULL
  355. } },
  356. sfxerror[] =
  357. {   "No errors.",
  358.     "Can't open file!",
  359.     "Can't read file!",
  360.     "Not an IFF 8SVX; too short!",
  361.     "Not an IFF FORM!",
  362.     "No memory for read!",
  363.     "Read error!",
  364.     "Malformed IFF; too short!",
  365.     "Not an IFF 8SVX!",
  366.     "No chip memory!"
  367. },
  368. objectdesc[LASTOBJECT + 1] =
  369. {   "AFFIXER: Stops protectors rotating.",
  370.     "AMMO: 5 bullets.",
  371.     "ARMOUR: Immune to most damage.",
  372.     "AUTOJUMP: Automagically jump. :-)",
  373.     "BONUS: Awards the next number.",
  374.     "BRAKES: Enables very slow speed.",
  375.     "CONVERTER: Fragments to missiles.",
  376.     "CUTTER: Cuts a tunnel through tail.",
  377.     "CYCLONE: Unleashes a cyclone.",
  378.     "ENCLOSER: Rectangular enclosure.",
  379.     "GLOW: Leaves a glowing tail.",
  380.     "GROWER: Enlarges silver and gold.",
  381.     "ICE: Freezes enemies.",
  382.     "LIGHTNING: Flashes around tail.",
  383.     "MAGNET: Attracts objects.",
  384.     "MINI BOMB: A minor explosion.",
  385.     "MINI HEALER: 5 lives.",
  386.     "MISSILE: A guided missile.",
  387.     "MULTIPLIER: More points.",
  388.     "POWER: Thicker bullets.",
  389.     "PROTECTOR: An orbiting companion.",
  390.     "PULSE: Fragment explosion.",
  391.     "PUSHER: Lets you push things.",
  392.     "REMNANTS: Bullets leave a trail.",
  393.     "SIDESHOT: Shoot sideways.",
  394.     "SLAYER: Smart bomb.",
  395.     "SLOWER: Slows creatures down.",
  396.     "SUPER BOMB: A major explosion.",
  397.     "SUPER HEALER: 20 lives.",
  398.     "SWITCHER: Changes tail colours.",
  399.     "TREASURE: Treasure level.",
  400.     "UMBRELLA: Skips 2-3 levels."
  401. };
  402.  
  403. MODULE struct
  404. {   WORD x, y;
  405.     STRPTR text;
  406. } about[ABOUTLINES + 1] =
  407. {   {72,  27, ABOUTSTRING                  },
  408.     {72,  35, RELEASEDATE                  },
  409.     {72,  51, COPYRIGHT                    },
  410.     {72,  59, "By James R. Jacobs"         },
  411.     {16,  75, "Fieldset size:       bytes" },
  412.     {16,  91, "Kickstart:"                 },
  413.     {16,  99, "Workbench:"                 }
  414. };
  415.  
  416. MODULE struct
  417. {   UBYTE scancode;
  418.     BYTE  player, deltax, deltay, special;
  419.     BOOL  down;
  420. } key[NUMKEYS + 1] =
  421. {   {Q,               0, -1, -1, MOVE,     FALSE},
  422.     {W,               0,  0, -1, MOVE,     FALSE},
  423.     {KEY_E,           0,  1, -1, MOVE,     FALSE},
  424.     {A,               0, -1,  0, MOVE,     FALSE},
  425.     {S,               0,  0,  1, MOVE,     FALSE},
  426.     {D,               0,  1,  0, MOVE,     FALSE},
  427.     {Z,               0, -1,  1, MOVE,     FALSE},
  428.     {KEY_X,           0,  1,  1, MOVE,     FALSE},
  429.     {C,               0,  1,  1, MOVE,     FALSE},
  430.     {NUMERICSEVEN,    1, -1, -1, MOVE,     FALSE},
  431.     {NUMERICEIGHT,    1,  0, -1, MOVE,     FALSE},
  432.     {NUMERICNINE,     1,  1, -1, MOVE,     FALSE},
  433.     {NUMERICFOUR,     1, -1,  0, MOVE,     FALSE},
  434.     {NUMERICFIVE,     1,  0,  1, MOVE,     FALSE},
  435.     {NUMERICSIX,      1,  1,  0, MOVE,     FALSE},
  436.     {NUMERICONE,      1, -1,  1, MOVE,     FALSE},
  437.     {NUMERICTWO,      1,  0,  1, MOVE,     FALSE},
  438.     {NUMERICTHREE,    1,  1,  1, MOVE,     FALSE},
  439.     {UP,              1,  0, -1, ONEHUMAN, FALSE},
  440.     {DOWN,            1,  0,  1, ONEHUMAN, FALSE},
  441.     {RIGHT,           1,  1,  0, ONEHUMAN, FALSE},
  442.     {LEFT,            1, -1,  0, ONEHUMAN, FALSE},
  443.     {SPACEBAR,        0,  0,  0, AMMO,     FALSE},
  444.     {NUMERICZERO,     1,  0,  0, AMMO,     FALSE},
  445.     {ENTER,           1,  0,  0, AMMO,     FALSE},
  446.     {HELP,            0,  0,  0, TRAINER,  FALSE},
  447.     {NUMERICSLASH,    0,  0,  0, TRAINER,  FALSE},
  448.     {NUMERICASTERISK, 0,  0,  0, TRAINER,  FALSE},
  449.     {NUMERICPLUS,     0,  0,  0, TRAINER,  FALSE},
  450.     {NUMERICMINUS,    0,  0,  0, TRAINER,  FALSE}
  451. }; /* Never leave unused keys in this structure. */
  452.  
  453. #define CREATUREHELPS 27
  454. MODULE struct
  455. {   UBYTE  image;
  456.     STRPTR desc;
  457. } creaturehelp[CREATUREHELPS + 1] =
  458. {   {ANT,           "Ant"       },
  459.     {BEAR,          "Bear"      },
  460.     {BIRD,          "Bird"      },
  461.     {BULL,          "Bull"      },
  462.     {CAMEL,         "Camel"     },
  463.     {CLOUD,         "Cloud"     },
  464.     {CYCLONE_C,     "Cyclone"   },
  465.     {DOG,           "Dog"       },
  466.     {ELEPHANT,      "Elephant"  },
  467.     {FISH,          "Fish"      },
  468.     {FROG,          "Frog"      },
  469.     {GIRAFFE,       "Giraffe"   },
  470.     {GOOSE,         "Goose"     },
  471.     {HORSE,         "Horse"     },
  472.     {KANGAROO,      "Kangaroo"  },
  473.     {MONKEY,        "Monkey"    },
  474.     {MOUSE,         "Mouse"     },
  475.     {ORB,           "Orb"       },
  476.     {OCTOPUS,       "Octopus"   },
  477.     {OTTER,         "Otter"     },
  478.     {LASTPROTECTOR, "Protector" },
  479.     {RABBIT,        "Rabbit"    },
  480.     {RAIN,          "Rain"      },
  481.     {SALAMANDER,    "Salamander"},
  482.     {SLIME,         "Slime"     },
  483.     {SNAIL,         "Snail"     },
  484.     {SPIDER,        "Spider"    },
  485.     {LASTHEAD,      "Worm"      }
  486. };
  487.  
  488. MODULE struct Chunk
  489. {   LONG          ckID;
  490.     LONG          ckSize;
  491.     LONG          ckType;
  492.     void*         ckData;
  493.     struct Chunk* ckNext;
  494. };
  495.  
  496. MODULE struct EasyStruct EasyStruct =
  497. {   sizeof(struct EasyStruct),
  498.     0,
  499.     TITLEBAR,
  500.     "Fieldset/highscores have been modified.",
  501.     "Continue|Cancel"
  502. };
  503.  
  504. // 7. MODULE FUNCTIONS ---------------------------------------------------
  505.  
  506. MODULE ABOOL beginfx(void);
  507. MODULE ABOOL firebutton(void);
  508. MODULE void freefx(void);
  509. MODULE void loadthefx(void);
  510. MODULE void loadthemusic(void);
  511. MODULE void matchtool(SBYTE player, char* s);
  512. MODULE void parsewb(void);
  513. MODULE UBYTE ReadJoystick(UWORD joynum);
  514.  
  515. MODULE ABOOL beginfx(void)
  516. {   AUTO    SBYTE i;
  517.     PERSIST    UBYTE    chan[] = {15};
  518.  
  519.     for (i = 0; i <= 3; i++)
  520.     {   eversent[i] = FALSE;
  521.         if (!(AudioPortPtr[i] = (struct MsgPort *) CreateMsgPort()))
  522.         {   freefx();
  523.             draw(MUSICICON, ICONY, BLACKENED);
  524.             mode = FALSE;
  525.             say("No port for effects!", RED);
  526.             anykey(TRUE);
  527.             return FALSE;
  528.         } else if (!(AudioRqPtr[i] = (struct IOAudio *) CreateIORequest(AudioPortPtr[i], sizeof(struct IOAudio))))
  529.         {   freefx();
  530.             draw(MUSICICON, ICONY, BLACKENED);
  531.             mode = FALSE;
  532.             say("No I/O memory for effects!", RED);
  533.             anykey(TRUE);
  534.             return FALSE;
  535.     }   }
  536.     AudioRqPtr[0]->ioa_Request.io_Message.mn_ReplyPort      = AudioPortPtr[0];
  537.     AudioRqPtr[0]->ioa_Request.io_Message.mn_Node.ln_Pri    = 127;
  538.     AudioRqPtr[0]->ioa_AllocKey                             = 0;
  539.     AudioRqPtr[0]->ioa_Data                                 = chan;
  540.     AudioRqPtr[0]->ioa_Length                               = 1;
  541.     if (AudioClosed = OpenDevice(AUDIONAME, 0L, (struct IORequest *) AudioRqPtr[0], 0L))
  542.     {   freefx();
  543.         draw(MUSICICON, ICONY, BLACKENED);
  544.         mode = FALSE;
  545.         say("Can't allocate all channels for effects!", RED);
  546.         anykey(TRUE);
  547.         return FALSE;
  548.     } else
  549.     {   for (i = 1; i <= 3; i++)
  550.             CopyMem(AudioRqPtr[0], AudioRqPtr[i], sizeof(struct IOAudio));
  551.         return TRUE;
  552. }   }
  553.  
  554. MODULE ABOOL firebutton(void)
  555. {   UBYTE PortState = ReadJoystick(1);
  556.  
  557.     if (PortState & JOYFIRE1) // don't check JOYFIRE2
  558.     {   return(TRUE);
  559.     } else return(FALSE);
  560. }
  561.  
  562. MODULE void freefx(void)
  563. {   SBYTE i;
  564.  
  565.     stopfx();
  566.     if (!AudioClosed)
  567.     {   CloseDevice((struct IORequest *) AudioRqPtr[0]);
  568.         AudioClosed = TRUE;
  569.     }
  570.     for (i = 0; i <= 3; i++)
  571.     {   if (AudioRqPtr[i])
  572.         {   DeleteIORequest(AudioRqPtr[i]);
  573.             AudioRqPtr[i] = NULL;
  574.         }
  575.         if (AudioPortPtr[i])
  576.         {   DeleteMsgPort(AudioPortPtr[i]);
  577.             AudioPortPtr[i] = NULL;
  578.     }   }
  579.     if (fbase)
  580.     {   FreeMem(fbase, fsize);
  581.         fbase = NULL;
  582.     }
  583.     if (FilePtr)
  584.     {   Close(FilePtr);
  585.         FilePtr = NULL;
  586. }   }
  587.  
  588. MODULE void loadthefx(void)
  589. {   UBYTE*        p8data;
  590.     TEXT          saystring[SAYLIMIT + 1];
  591.     SBYTE         code = 0, i,
  592.                   iobuffer[8]; /* buffer for 8SVX.VHDR  */
  593.     SBYTE*        psample[2];  /* sample pointers */
  594.     struct Chunk* p8Chunk;     /* pointers for 8SVX parsing */
  595.     Voice8Header* pVoice8Header = NULL; // only set to NULL to avoid spurious warnings
  596.     ULONG         rd8count;
  597.  
  598.     say("Loading sound effects...", WHITE);
  599.     fxable = SUCCEEDED;
  600.  
  601.     for (i = 0; i <= SAMPLES; i++)
  602.         samp[i].base = NULL;
  603.  
  604.     for (i = 0; i <= SAMPLES; i++)
  605.     {   if (!(FilePtr = Open(samp[i].filename, MODE_OLDFILE)))
  606.             code = 1;                               /* can't open file */
  607.         else
  608.         {   rd8count = Read(FilePtr, iobuffer, 8L);
  609.             if (rd8count == -1)
  610.                 code = 2;                           /* can't read file */
  611.             elif (rd8count < 8)
  612.                 code = 3;                           /* not an IFF 8SVX; too short */
  613.             else
  614.             {   p8Chunk = (struct Chunk *) iobuffer;
  615.                 if (p8Chunk->ckID != ID_FORM)
  616.                     code = 4;                       /* not an IFF FORM */
  617.                 elif (!(fbase = (UBYTE *) AllocMem(fsize = p8Chunk->ckSize, MEMF_PUBLIC | MEMF_CLEAR)))
  618.                     code = 5;                       /* no memory for read */
  619.                 else
  620.                 {   p8data = fbase;
  621.                     rd8count = Read(FilePtr, p8data, p8Chunk->ckSize);
  622.                     if (rd8count == -1)
  623.                         code = 6;                   /* read error */
  624.                     elif (rd8count < p8Chunk->ckSize)
  625.                         code = 7;                   /* malformed IFF; too short */
  626.                     elif (MAKE_ID(*p8data, *(p8data + 1), *(p8data + 2), *(p8data + 3)) != ID_8SVX)
  627.                         code = 8;                   /* not an IFF 8SVX */
  628.                     else
  629.                     {   p8data = p8data + 4;
  630.                         while (p8data < fbase + fsize)
  631.                         {   p8Chunk = (struct Chunk *) p8data;
  632.                             switch(p8Chunk->ckID)
  633.                             {
  634.                             case ID_VHDR:
  635.                                 pVoice8Header     = (Voice8Header *) (p8data + 8L);
  636.                             break;
  637.                             case ID_BODY:
  638.                                 psample[0]        = (SBYTE *) (p8data + 8L);
  639.                                 psample[1]        = psample[0] + pVoice8Header->oneShotHiSamples;
  640.                                 samp[i].length[0] = (ULONG) pVoice8Header->oneShotHiSamples;
  641.                                 samp[i].length[1] = (ULONG) pVoice8Header->repeatHiSamples;
  642.  
  643.                                 /* To grab the volume level from the IFF
  644.                                 8SVX file itself, add this line here:
  645.  
  646.                                 samp[i].volume    = (SBYTE) (pVoice8Header->volume / 156); */
  647.                             break;
  648.                             default:
  649.                             break;
  650.                             }
  651.                             p8data += 8L + p8Chunk->ckSize;
  652.                             if (p8Chunk->ckSize & 1L == 1)
  653.                                 p8data++;
  654.                         }
  655.                         if (samp[i].length[0] == 0)
  656.                             samp[i].bank = 1;
  657.                         else samp[i].bank = 0;
  658.                         if (samp[i].length[samp[i].bank] <= 102400)
  659.                             samp[i].size = samp[i].length[samp[i].bank];
  660.                         else samp[i].size = 102400;
  661.                         samp[i].base = (UBYTE *) AllocMem(samp[i].size, MEMF_CHIP | MEMF_CLEAR);
  662.                         if (!samp[i].base)
  663.                             code = 9; /* no chip memory */
  664.                         else
  665.                         {   CopyMem(psample[samp[i].bank], samp[i].base, samp[i].size);
  666.                             psample[samp[i].bank] += samp[i].size;
  667.                             if (GfxBase->DisplayFlags & PAL) // PAL clock
  668.                             {   samp[i].speed = PALCLOCK / pVoice8Header->samplesPerSec;
  669.                             } else // NTSC clock
  670.                             {   samp[i].speed = NTSCCLOCK / pVoice8Header->samplesPerSec;
  671.                             }
  672.  
  673. /* "The maximum frequency achievable depends on the screen rate because
  674. the Paula audio DMA period depends on the horizontal refresh rate, but the
  675. actual clock rate of Paula by which the audio DA converters are driven
  676. depends really only on the clock rate.
  677.  
  678. It's fixed for either PAL or NTSC machines, NOT for PAL or NTSC screen
  679. modes. Hence just the two values that are given in the RKRMs are
  680. completely sufficient. Note that running an NTSC screen on a PAL machine
  681. does not change the system clock and hence neither the audio frequency.
  682. It changes horizontal timing and vertical timing, and hence the minimal
  683. audio period." - Thomas `Thor' Richter. */
  684.  
  685.                             if (fbase)
  686.                             {   FreeMem(fbase, fsize);
  687.                                 fbase = NULL;
  688.                             }
  689.                             if (FilePtr)
  690.                             {   Close(FilePtr);
  691.                                 FilePtr = NULL;
  692.         }   }   }   }   }   }
  693.         if (code)
  694.         {   freefx();
  695.             fxable = FAILED;
  696.             strcpy(saystring, samp[i].filename);
  697.             strcat(saystring, ": ");
  698.             strcat(saystring, sfxerror[code]);
  699.             say(saystring, RED);
  700.             anykey(TRUE);
  701.             break;
  702. }   }   }
  703.  
  704. MODULE void loadthemusic(void)
  705. {   if (!(MEDPlayerBase = OpenLibrary("medplayer.library", 0L)))
  706.     {   say("Can't open MEDPlayer.library!", RED);
  707.         anykey(TRUE);
  708.     } else
  709.     {   say("Loading music...", WHITE);
  710.         if
  711.         (   (SongPtr[0] = (struct MMD0 *) LoadModule("PROGDIR:music/title.MED"))
  712.          && (SongPtr[1] = (struct MMD0 *) LoadModule("PROGDIR:music/over.MED"))
  713.          && (SongPtr[2] = (struct MMD0 *) LoadModule("PROGDIR:music/editor.MED"))
  714.          && (SongPtr[3] = (struct MMD0 *) LoadModule("PROGDIR:music/bonus.MED"))
  715.          && (SongPtr[4] = (struct MMD0 *) LoadModule("PROGDIR:music/game1.MED"))
  716.          && (SongPtr[5] = (struct MMD0 *) LoadModule("PROGDIR:music/game2.MED"))
  717.          && (SongPtr[6] = (struct MMD0 *) LoadModule("PROGDIR:music/game3.MED"))
  718.         )
  719.         {   musicable = SUCCEEDED;
  720.         } else
  721.         {   say("Can't load music!", RED);
  722.             anykey(TRUE);
  723. }   }   }
  724.  
  725. MODULE void matchtool(SBYTE player, char* s)
  726. {   if (player <= 1 && (MatchToolValue(s, "KYBD") || MatchToolValue(s, "KEYBOARD")))
  727.     {   worm[player].control = KEYBOARD;
  728.     } elif (MatchToolValue(s, "JOY") || MatchToolValue(s, "STICK") || MatchToolValue(s, "JOYSTICK"))
  729.     {   worm[player].control = JOYSTICK;
  730.     } elif (MatchToolValue(s, "GAMEPAD") || MatchToolValue(s, "PAD"))
  731.     {   if (!LowLevelBase)
  732.         {   Printf("Worm Wars: Can't open lowlevel.library!\n");
  733.             cleanexit(EXIT_FAILURE);
  734.         }
  735.         worm[player].control = GAMEPAD;
  736.     } elif (MatchToolValue(s, "AMIGA"))
  737.     {   worm[player].control = AMIGA;
  738.     } elif (MatchToolValue(s, "NONE"))
  739.     {   worm[player].control = NONE;
  740. }   }
  741.  
  742. MODULE void parsewb(void)
  743. {   struct DiskObject* DiskObject;
  744.     STRPTR*            ToolArray;
  745.     STRPTR             s;
  746.  
  747.     if ((*WBArg->wa_Name) && (DiskObject = GetDiskObject(WBArg->wa_Name)))
  748.     {   ToolArray = (STRPTR *) DiskObject->do_ToolTypes;
  749.  
  750.         if (s = FindToolType(ToolArray, "NOPRELOAD"))
  751.         {   fxable = musicable = DEFER;
  752.         }
  753.         if (s = FindToolType(ToolArray, "NOANIMS"   ))
  754.         {   anims = FALSE;
  755.         }
  756.         if (s = FindToolType(ToolArray, "NOICONS"   ))
  757.         {   icons = FALSE;
  758.         }
  759.         if (s = FindToolType(ToolArray, "SHUFFLE"   ))
  760.         {   randomflag = TRUE;
  761.         }
  762.         if (s = FindToolType(ToolArray, "QUIET"     ))
  763.         {   quiet = TRUE;
  764.         }
  765.         if (s = FindToolType(ToolArray, "FILE"      ))
  766.         {   strcpy(pathname, WBArg->wa_Name);
  767.         }
  768.         if (s = FindToolType(ToolArray, "GREEN"     ))
  769.         {   matchtool(0, s);
  770.         }
  771.         if (s = FindToolType(ToolArray, "RED"       ))
  772.         {   matchtool(1, s);
  773.         }
  774.         if (s = FindToolType(ToolArray, "BLUE"      ))
  775.         {   matchtool(2, s);
  776.         }
  777.         if (s = FindToolType(ToolArray, "YELLOW"    ))
  778.         {   matchtool(3, s);
  779.         }
  780.         FreeDiskObject(DiskObject);
  781. }   }
  782.  
  783. MODULE UBYTE ReadJoystick(UWORD joynum)
  784. {
  785. #ifdef LATTICE
  786.      extern struct Custom far custom;
  787. #endif
  788. #ifdef __STORM__
  789.      extern struct Custom custom;
  790. #endif
  791.  
  792.     UBYTE ret = 0;
  793.     UWORD joy;
  794.  
  795.     if (joynum == 0)
  796.         joy = custom.joy0dat;
  797.     else joy = custom.joy1dat;
  798.  
  799.     ret += (joy >> 1 ^ joy) & 0x0100 ? JOYUP : 0;
  800.     ret += (joy >> 1 ^ joy) & 0x0001 ? JOYDOWN : 0;
  801.     ret += joy & 0x0200 ? JOYLEFT : 0;
  802.     ret += joy & 0x0002 ? JOYRIGHT : 0;
  803.  
  804.     if (joynum == 0)
  805.     {   ret += !(CIAPtr->ciapra & 0x0040) ? JOYFIRE1 : 0; /* read firebuttons */
  806.         ret += !(POTGOR & 0x0400) ? JOYFIRE2 : 0;         /* on joyport 0 */
  807.     } else
  808.     {   ret += !(CIAPtr->ciapra & 0x0080) ? JOYFIRE1 : 0; /* read firebuttons */
  809.         ret += !(POTGOR & 0x0400) ? JOYFIRE2 : 0;         /* on joyport 1 */
  810.     }
  811.  
  812.     return(ret);
  813. }
  814.  
  815. // 8. EXPORTED FUNCTIONS -------------------------------------------------
  816.  
  817. EXPORT int main(int argc, char** argv)
  818. {
  819. BPTR                        FileHandle,
  820.                             OldDir;
  821. SBYTE                       player,
  822.                             which;
  823. TEXT                        saystring[SAYLIMIT + 1];
  824. SWORD                       oldsecondsleft = -1;
  825. ULONG                       fonttag,
  826.                             publictag;
  827. SLONG                       i,
  828.                             args[11] = {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L};
  829. struct ScreenModeRequester* smr;
  830. ULONG                       elapsed;
  831. ABOOL                       ok;
  832. UWORD Pens[13] =
  833. {       BLACK,     /* DETAILPEN            text in title bar */
  834.         WHITE,     /* BLOCKPEN             fill title bar */
  835.         BLACK,     /* TEXTPEN              regular text on BACKGROUNDPEN */
  836.         WHITE,     /* SHINEPEN             bright edge */
  837.         MEDIUMGREY,/* SHADOWPEN            dark edge */
  838.         BLUE,      /* FILLPEN              filling active window borders
  839.                                            and selected gadgets */
  840.         BLACK,     /* FILLTEXTPEN          text rendered over FILLPEN */
  841.         LIGHTGREY, /* BACKGROUNDPEN        background colour */
  842.         RED,       /* HIGHLIGHTTEXTPEN     highlighted text on BACKGROUNDPEN */
  843.         BLACK,     /* BARDETAILPEN         text/detail in screen-bar/menus */
  844.         WHITE,     /* BARBLOCKPEN          screen-bar/menus fill */
  845.         BLACK,     /* BARTRIMPEN           trim under screen-bar */
  846.         (UWORD) ~0 /* and used against BLOCKPEN in ASL save requesters */
  847. };
  848. struct ColorSpec Colours[] =
  849. {   { 0, 0x0, 0x0, 0x0}, // black
  850.     { 1, 0xA, 0xA, 0xA}, // light grey
  851.     { 2, 0x3, 0x6, 0x3}, // dark green
  852.     { 3, 0x7, 0x6, 0x3}, // dark yellow
  853.     { 4, 0x6, 0x6, 0x6}, // medium grey
  854.     { 5, 0x4, 0x4, 0xA}, // dark blue
  855.     { 6, 0x8, 0x8, 0xF}, // light blue
  856.     { 7, 0x7, 0xB, 0x7}, // light green
  857.     { 8, 0x9, 0x3, 0x3}, // dark red
  858.     { 9, 0x8, 0x4, 0x2}, // brown
  859.     {10, 0xF, 0x5, 0x5}, // light red
  860.     {11, 0xB, 0xB, 0x6}, // light yellow
  861.     {12, 0x3, 0x3, 0x3}, // dark grey
  862.     {13, 0xF, 0x9, 0x8}, // orange
  863.     {14, 0xF, 0x8, 0xF}, // purple
  864.     {15, 0xF, 0xF, 0xF}, // white
  865.     {16, 0x0, 0x0, 0x0},
  866.     {17, 0x1, 0x1, 0x1},
  867.     {18, 0x2, 0x2, 0x2},
  868.     {19, 0x3, 0x3, 0x3},
  869.     {20, 0x4, 0x4, 0x4},
  870.     {21, 0x5, 0x5, 0x5},
  871.     {22, 0x6, 0x6, 0x6},
  872.     {23, 0x7, 0x7, 0x7},
  873.     {24, 0x8, 0x8, 0x8},
  874.     {25, 0x9, 0x9, 0x9},
  875.     {26, 0xA, 0xA, 0xA},
  876.     {27, 0xB, 0xB, 0xB},
  877.     {28, 0xC, 0xC, 0xC},
  878.     {29, 0xD, 0xD, 0xD},
  879.     {30, 0xE, 0xE, 0xE},
  880.     {31, 0xF, 0xF, 0xF},
  881.     {-1, NULL,NULL,NULL}
  882. };
  883. struct TextAttr WormWars8 =
  884. {   "WormWars.font", 8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
  885. },              Topaz8 =
  886. {   "topaz.font", 8, FS_NORMAL,  FPF_ROMFONT | FPF_DESIGNED
  887. };
  888.  
  889.     // Start of program.
  890.  
  891.     // version embedding into executable
  892.     if (0) /* that is, never */
  893.     {   say(VERSION, ANYTHING);
  894.     }
  895.  
  896.     if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37L)))
  897.     {   Write(Output(), OLDKICKSTART, strlen(OLDKICKSTART));
  898.         cleanexit(EXIT_FAILURE);
  899.     }
  900.  
  901.     /* From this point onwards, we can be sure we have Kickstart 2.04+... */
  902.  
  903.     for (i = 0; i <= SAMPLES; i++)
  904.     {   samp[i].base = NULL;
  905.     }
  906.     enginesetup();
  907.     ProcessPtr = (struct Process *) FindTask(NULL);
  908.  
  909.  
  910.     if (SysBase->LibNode.lib_Version < 36L)
  911.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Need exec.library V36+!\0", 24);
  912.         cleanexit(EXIT_FAILURE);
  913.     }
  914.     if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L)))
  915.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open graphics.library!\0", 24);
  916.         cleanexit(EXIT_FAILURE);
  917.     }
  918.     if (!(GadToolsBase = OpenLibrary("gadtools.library", 37L)))
  919.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open GadTools.library V37+!\0", 24);
  920.         cleanexit(EXIT_FAILURE);
  921.     }
  922.     if (!(ASLBase = OpenLibrary("asl.library", 0L)))
  923.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open ASL.library!\0", 24);
  924.         cleanexit(EXIT_FAILURE);
  925.     }
  926.     if (!(UtilityBase = (struct UtilityBase *) OpenLibrary("utility.library", 0L)))
  927.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open utility.library!\0", 24);
  928.         cleanexit(EXIT_FAILURE);
  929.     }
  930.     if (!(IconBase = OpenLibrary("icon.library", 0L)))
  931.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open icon.library!\0", 24);
  932.         cleanexit(EXIT_FAILURE);
  933.     }
  934.     LowLevelBase = OpenLibrary("lowlevel.library", 0L);
  935.  
  936.     ok = FALSE;
  937.     if (FileHandle = Open("PROGDIR:WormWars.config", MODE_OLDFILE))
  938.     {   if (Read(FileHandle, ConfigBuffer, CONFIGLENGTH) == CONFIGLENGTH)
  939.         {   ok = TRUE;
  940.             for (player = 0; player <= 3; player++)
  941.             {   worm[player].control = (UBYTE) ConfigBuffer[player];
  942.             }
  943.             DisplayID     = (ULONG) (  (ConfigBuffer[ 4] * 16777216)
  944.                                      + (ConfigBuffer[ 5] *    65536)
  945.                                      + (ConfigBuffer[ 6] *      256)
  946.                                      +  ConfigBuffer[ 7]            );
  947.             DisplayWidth  = (ULONG) (  (ConfigBuffer[ 8] * 16777216)
  948.                                      + (ConfigBuffer[ 9] *    65536)
  949.                                      + (ConfigBuffer[10] *      256)
  950.                                      +  ConfigBuffer[11]            );
  951.             DisplayHeight = (ULONG) (  (ConfigBuffer[12] * 16777216)
  952.                                      + (ConfigBuffer[13] *    65536)
  953.                                      + (ConfigBuffer[14] *      256)
  954.                                      +  ConfigBuffer[15]            );
  955.             DisplayDepth  = (UWORD) (  (ConfigBuffer[16] *      256)
  956.                                      +  ConfigBuffer[17]            );
  957.             randomflag    = (ABOOL)     ConfigBuffer[18];
  958.             icons         = (ABOOL)     ConfigBuffer[19];
  959.             anims         = (ABOOL)     ConfigBuffer[20];
  960.             titlebar      = (ABOOL)     ConfigBuffer[21];
  961.             engraved      = (ABOOL)     ConfigBuffer[22];
  962.         }
  963.         Close(FileHandle);
  964.         // FileHandle = NULL;
  965.     }
  966.  
  967. /* argument parsing */
  968.  
  969. if (argc) /* started from CLI */
  970. {   if (!(ArgsPtr = ReadArgs
  971.     (   "-N=NOPRELOAD/S,-A=NOANIMS/S,-I=NOICONS/S,-P=PRI/K/N,"
  972.         "-S=SHUFFLE/S,-Q=QUIET/S,GREEN/K,RED/K,BLUE/K,YELLOW/K,FILE",
  973.         (LONG *) args,
  974.         NULL
  975.     )))
  976.     {   Printf
  977.         (   "Usage: %s [-n=NOPRELOAD] [-a=NOANIMS] [-i=NOICONS] "
  978.             "[-p=PRI <priority>] [-s=SHUFFLE] [-q=QUIET] "
  979.             "[GREEN=JOY|PAD|AMIGA|NONE|KYBD] "
  980.               "[RED=JOY|PAD|AMIGA|NONE|KYBD] "
  981.              "[BLUE=JOY|PAD|AMIGA|NONE] "
  982.            "[YELLOW=JOY|PAD|AMIGA|NONE] "
  983.             "[[FILE=]<levelset>]\n",
  984.             argv[0]
  985.         );
  986.         cleanexit(EXIT_FAILURE);
  987.     }
  988.     if (args[0])
  989.     {   fxable = musicable = DEFER;
  990.     }
  991.     if (args[1])
  992.     {   anims = FALSE;
  993.     }
  994.     if (args[2])
  995.     {   icons = FALSE;
  996.     }
  997.     if (args[3])
  998.     {   if (args[3] < -128 || args[3] > 5)
  999.         {   Printf("%s: Priority range is -128 to +5\n", argv[0]);
  1000.             cleanexit(EXIT_FAILURE);
  1001.         }
  1002.         OldPri = SetTaskPri((struct Task *) ProcessPtr, args[3]);
  1003.     }
  1004.     if (args[4])
  1005.     {   randomflag = TRUE;
  1006.     }
  1007.     if (args[5])
  1008.     {   quiet = TRUE;
  1009.     }
  1010.  
  1011.     for (player = 0; player <= 3; player++)
  1012.     {   if (args[player + 6])
  1013.         {   if
  1014.             (   player <= 1
  1015.              && (   (!stricmp((STRPTR) args[player + 6], "KYBD"    ))
  1016.                  || (!stricmp((STRPTR) args[player + 6], "KEYBOARD"))
  1017.             )   )
  1018.             {   worm[player].control = KEYBOARD;
  1019.             } elif
  1020.             (   (!stricmp((STRPTR) args[player + 6], "JOY"     ))
  1021.              || (!stricmp((STRPTR) args[player + 6], "STICK"   ))
  1022.              || (!stricmp((STRPTR) args[player + 6], "JOYSTICK"))
  1023.             )
  1024.             {   worm[player].control = JOYSTICK;
  1025.             } elif
  1026.             (   (!stricmp((STRPTR) args[player + 6], "GAMEPAD"))
  1027.              || (!stricmp((STRPTR) args[player + 6], "PAD"    ))
  1028.             )
  1029.             {   if (!LowLevelBase)
  1030.                 {   Printf("%s: Can't open lowlevel.library!\n", argv[0]);
  1031.                     cleanexit(EXIT_FAILURE);
  1032.                 }
  1033.                 worm[player].control = GAMEPAD;
  1034.             } elif (!stricmp((STRPTR) args[player + 6], "AMIGA"))
  1035.             {   worm[player].control = AMIGA;
  1036.             } elif (!stricmp((STRPTR) args[player + 6], "NONE"))
  1037.             {   worm[player].control = NONE;
  1038.             } else
  1039.             {   if (player <= 1)
  1040.                 {   Printf("%s: Worm %ld control must be JOY|PAD|AMIGA|NONE|KYBD\n", (SLONG) player, argv[0]);
  1041.                 } else
  1042.                 {   Printf("%s: Worm %ld control must be JOY|PAD|AMIGA|NONE\n", (SLONG) player, argv[0]);
  1043.                 }
  1044.                 cleanexit(EXIT_FAILURE);
  1045.     }   }   }
  1046.  
  1047.     if (args[10])
  1048.     {   strcpy(pathname, (STRPTR) args[10]);
  1049. }   }
  1050. else /* started from WB */
  1051. {   WBMsg = (struct WBStartup *) argv;
  1052.     WBArg = WBMsg->sm_ArgList; /* head of the arg list */
  1053.  
  1054.     for (i = 0;
  1055.          i < WBMsg->sm_NumArgs;
  1056.          i++, WBArg++)
  1057.     {   if (WBArg->wa_Lock)
  1058.         {    /* something that does not support locks */
  1059.              parsewb();
  1060.         }
  1061.         else
  1062.         {    /* locks supported, change to the proper directory */
  1063.              OldDir = CurrentDir(WBArg->wa_Lock);
  1064.              parsewb();
  1065.              CurrentDir(OldDir);
  1066.         }
  1067.         if (i == 1)
  1068.         {    strcpy(pathname, WBArg->wa_Name);
  1069. }   }   }
  1070.  
  1071. if (!(TimeValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
  1072. {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't allocate timer value structure!\0", 24);
  1073.     cleanexit(EXIT_FAILURE);
  1074. }
  1075. if (!(TimerPortPtr = (struct MsgPort *) CreateMsgPort()))
  1076. {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't allocate timer message port!\0", 24);
  1077.     cleanexit(EXIT_FAILURE);
  1078. }
  1079. if (!(TimerRqPtr = (struct timerequest *) CreateIORequest(TimerPortPtr, sizeof(struct timerequest))))
  1080. {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create timer I/O request!\0", 24);
  1081.     cleanexit(EXIT_FAILURE);
  1082. }
  1083. if (TimerClosed = OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerRqPtr, 0))
  1084. {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open timer.device!\0", 24);
  1085.     cleanexit(EXIT_FAILURE);
  1086. }
  1087. TimerBase = TimerRqPtr->tr_node.io_Device;
  1088.  
  1089.     if (!ok && ASLBase->lib_Version >= 38L)
  1090.     {   if (!(smr = (struct ScreenModeRequester *) AllocAslRequestTags
  1091.         (   ASL_ScreenModeRequest,
  1092.             ASLSM_TitleText,            "Worm Wars: Screen Mode Requester",
  1093.             ASLSM_InitialDisplayID,     HIRES_KEY | PAL_MONITOR_ID | LACE,
  1094.             ASLSM_InitialDisplayWidth,  ENTIREXPIXEL,
  1095.             ASLSM_InitialDisplayHeight, ENTIREYPIXEL,
  1096.             ASLSM_InitialDisplayDepth,  DEPTH5,
  1097.             ASLSM_DoWidth,              TRUE,
  1098.             ASLSM_DoHeight,             TRUE,
  1099.             ASLSM_DoDepth,              TRUE,
  1100.             ASLSM_MinWidth,             ENTIREXPIXEL,
  1101.             ASLSM_MinHeight,            ENTIREYPIXEL,
  1102.             ASLSM_MinDepth,             DEPTH4,
  1103.             TAG_DONE
  1104.         )))
  1105.         {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create ASL screen mode request!\0", 24);
  1106.             cleanexit(EXIT_FAILURE);
  1107.         }
  1108.         if (AslRequest(smr, 0L))
  1109.         {   DisplayID     = smr->sm_DisplayID;
  1110.             DisplayWidth  = smr->sm_DisplayWidth;
  1111.             DisplayHeight = smr->sm_DisplayHeight;
  1112.             DisplayDepth  = smr->sm_DisplayDepth;
  1113.             FreeAslRequest(smr);
  1114.         } else
  1115.         {   FreeAslRequest(smr);
  1116.             cleanexit(EXIT_SUCCESS);
  1117.     }   }
  1118.  
  1119.     /* PREPARE DISPLAY -----------------------------------------------
  1120.  
  1121.     font and screen */
  1122.  
  1123.     if (LockPubScreen("WORMWARS"))
  1124.     {   publictag = TAG_IGNORE;
  1125.     } else
  1126.     {   publictag = SA_PubName;
  1127.     }
  1128.  
  1129.     if
  1130.     (   (DiskFontBase = OpenLibrary("diskfont.library", 0L))
  1131.      && (FontPtr = (struct TextFont *) OpenDiskFont(&WormWars8))
  1132.     )
  1133.     {   fonttag = (ULONG) &WormWars8;
  1134.     } else
  1135.     {   fonttag = (ULONG) &Topaz8;
  1136.     }
  1137.  
  1138.     ScreenPtr = (struct Screen *) OpenScreenTags
  1139.     (   NULL,
  1140.         SA_Width,       DisplayWidth,
  1141.         SA_Height,      DisplayHeight,
  1142.         SA_Depth,       DisplayDepth,
  1143.         SA_DisplayID,   DisplayID,
  1144.         SA_Behind,      TRUE,
  1145.         SA_AutoScroll,  TRUE,
  1146.         SA_ShowTitle,   titlebar,
  1147.         SA_Title,       TITLEBAR,
  1148.         SA_Colors,      Colours,
  1149.         SA_Font,        fonttag,
  1150.         SA_Pens,        Pens,
  1151.         publictag,      "WORMWARS",
  1152.         TAG_DONE
  1153.     );
  1154.     if (!ScreenPtr)
  1155.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open screen!\0", 24);
  1156.         cleanexit(EXIT_FAILURE);
  1157.     }
  1158.  
  1159.     saveconfig = TRUE;
  1160.  
  1161.     if (publictag == SA_PubName)
  1162.     {   PubScreenStatus(ScreenPtr, NULL); // take the screen public
  1163.     }
  1164.  
  1165.     if (DisplayWidth > MAXXSIZE)
  1166.     {   DisplayWidth = MAXXSIZE;
  1167.     }
  1168.     if (DisplayHeight > MAXYSIZE)
  1169.     {   DisplayHeight = MAXYSIZE;
  1170.     }
  1171.  
  1172.     fieldx = ((DisplayWidth  - 88         ) / 12) - 2;
  1173.     fieldy = ((DisplayHeight - 16 - TBSIZE) / 12) - 1;
  1174.  
  1175.     /* For some reason, we lose 4 memory chunks around this point: 2 chunks
  1176.     each of 292 bytes and 10 bytes. It is related to OpenScreenTagList(),
  1177.     but is not related to the SA_Colors, SA_Font or SA_Pens tags, nor to
  1178.     the timer.device. Perhaps it is due to the public nature of the screen?
  1179.  
  1180.     These must be done before the menus are set up */
  1181.     if (anims)
  1182.     {   NewMenu[INDEX_ANIMATIONS].nm_Flags |= CHECKED;
  1183.     }
  1184.     if (icons)
  1185.     {   NewMenu[INDEX_CREATEICONS].nm_Flags |= CHECKED;
  1186.     }
  1187.     if (titlebar)
  1188.     {   NewMenu[INDEX_SHOWTITLEBAR].nm_Flags |= CHECKED;
  1189.     }
  1190.     if (engraved)
  1191.     {   NewMenu[INDEX_ENGRAVEDSQUARES].nm_Flags |= CHECKED;
  1192.     }
  1193.  
  1194.     /* GadTools */
  1195.     if
  1196.     (   !(    CycleGadget.ng_VisualInfo
  1197.           =  StringGadget.ng_VisualInfo
  1198.           = ShuffleGadget.ng_VisualInfo
  1199.           =  VisualInfoPtr = (APTR) GetVisualInfo(ScreenPtr, TAG_DONE)
  1200.     )   )
  1201.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't get GadTools visual info!\0", 24);
  1202.         cleanexit(EXIT_FAILURE);
  1203.     }
  1204.     if (!(MenuPtr = (struct Menu *) CreateMenus(NewMenu, TAG_DONE)))
  1205.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create menus!\0", 24);
  1206.         cleanexit(EXIT_FAILURE);
  1207.     }
  1208.     if (!(LayoutMenus(MenuPtr, VisualInfoPtr, GTMN_NewLookMenus, TRUE, TAG_DONE)))
  1209.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't lay out menus!\0", 24);
  1210.     cleanexit(EXIT_FAILURE);
  1211.     }
  1212.     if (!(PrevGadgetPtr = (struct Gadget *) CreateContext(&GListPtr)))
  1213.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create GadTools context!\0", 24);
  1214.     cleanexit(EXIT_FAILURE);
  1215.     }
  1216.  
  1217.     for (player = 0; player <= 3; player++)
  1218.     {   CycleGadget.ng_LeftEdge = CENTREXPIXEL - (4 * FONTX);
  1219.         CycleGadget.ng_TopEdge  = YSTART + 253 + (player * (FONTY + 5));
  1220.         CycleGadgetPtr[player] = PrevGadgetPtr = (struct Gadget *) CreateGadget
  1221.         (   CYCLE_KIND,
  1222.             PrevGadgetPtr,
  1223.             &CycleGadget,
  1224.             GTCY_Labels,   CycleOptions[player],
  1225.             GTCY_Active,   worm[player].control,
  1226.             GT_Underscore, '_',
  1227.             GA_Disabled,   TRUE,
  1228.         TAG_DONE);
  1229.     }
  1230.  
  1231.     ShuffleGadget.ng_LeftEdge = CENTREXPIXEL + (7 * FONTX);
  1232.     ShuffleGadget.ng_TopEdge  = YSTART + 319;
  1233.     ShuffleGadgetPtr = PrevGadgetPtr = (struct Gadget *) CreateGadget
  1234.     (   CHECKBOX_KIND,
  1235.         PrevGadgetPtr,
  1236.         &ShuffleGadget,
  1237.         GTCB_Checked,  randomflag,
  1238.         GT_Underscore, '_',
  1239.         GA_Disabled,   TRUE,
  1240.     TAG_DONE);
  1241.  
  1242.     /* main window */
  1243.     if (!(MainWindowPtr = (struct Window *) OpenWindowTags(NULL,
  1244.         WA_Top,                 0,
  1245.         WA_Width,               DisplayWidth,
  1246.         WA_Height,              DisplayHeight,
  1247.         WA_IDCMP,               IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_CLOSEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MENUPICK | IDCMP_MENUVERIFY | CYCLEIDCMP | STRINGIDCMP | CHECKBOXIDCMP | IDCMP_REFRESHWINDOW | IDCMP_INTUITICKS,
  1248.         WA_Gadgets,             GListPtr,
  1249.     WA_CustomScreen,    ScreenPtr,
  1250.         WA_Backdrop,            TRUE,
  1251.     WA_Borderless,        TRUE,
  1252.     WA_Activate,        TRUE,
  1253.     WA_SmartRefresh,    TRUE,
  1254.         WA_ReportMouse,         TRUE,
  1255.     WA_RptQueue,        16,
  1256.         WA_NewLookMenus,        TRUE,
  1257.     TAG_DONE)))
  1258.         {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open main window!\0", 24);
  1259.             cleanexit(EXIT_FAILURE);
  1260.     }
  1261.  
  1262.     /* redirection of AmigaDOS system requesters */
  1263.     OldWindowPtr = ProcessPtr->pr_WindowPtr;
  1264.     ProcessPtr->pr_WindowPtr = (APTR) MainWindowPtr;
  1265.  
  1266.     if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, PATTERN, ASL_Window, MainWindowPtr, TAG_DONE)))
  1267.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create ASL request!\0", 24);
  1268.         cleanexit(EXIT_FAILURE);
  1269.     }
  1270.  
  1271.     /* String gadgets: first the window is opened with the cycle and
  1272.     checkbox gadgets.
  1273.       It is necessary not to display the string gadgets yet, so the
  1274.     gadgets are then created and added to the gadget list. You will note
  1275.     there is no command given to render them as yet. When the attributes
  1276.     are modified at highscore time, the applicable gadget is refreshed
  1277.     then. */
  1278.  
  1279.     for (which = 0; which <= HISCORES; which++)
  1280.     {   StringGadget.ng_LeftEdge = CENTREXPIXEL - 85;
  1281.         StringGadget.ng_TopEdge  = YSTART + 133 + (which * HISCOREDISTANCE);
  1282.         StringGadgetPtr[which] = PrevGadgetPtr = (struct Gadget *) CreateGadget(STRING_KIND, PrevGadgetPtr, &StringGadget, GTST_MaxChars, NAMELENGTH, STRINGA_ReplaceMode, TRUE, GA_Disabled, TRUE, TAG_DONE);
  1283.     }
  1284.     if (!PrevGadgetPtr)
  1285.     {   DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create GadTools gadgets!\0", 24);
  1286.     cleanexit(EXIT_FAILURE);
  1287.     }
  1288.  
  1289.     ScreenToFront(ScreenPtr);
  1290.  
  1291.     if (musicable == UNTRIED)
  1292.         loadthemusic();
  1293.     if (fxable == UNTRIED)
  1294.         loadthefx();
  1295.     if (musicable == SUCCEEDED)
  1296.         toggle(M);
  1297.     elif (fxable == SUCCEEDED)
  1298.         toggle(F);
  1299.  
  1300.     strcpy(saystring, "Loading ");
  1301.     strcat(saystring, pathname);
  1302.     strcat(saystring, "...");
  1303.     say(saystring, WHITE);
  1304.     if (loadfields(pathname))
  1305.     {   if (!quiet)
  1306.         {   strcpy(saystring, "Can't open ");
  1307.             strcat(saystring, pathname);
  1308.             strcat(saystring, "!");
  1309.             say(saystring, RED);
  1310.         }
  1311.         newfields();
  1312.         if (!quiet)
  1313.         {   anykey(TRUE);
  1314.     }   }
  1315.  
  1316.     while (1)
  1317.     {   titlescreen();
  1318.         for (i = 0; i <= 3; i++)
  1319.         {   if (worm[i].control == GAMEPAD)
  1320.             {   SetJoyPortAttrs(worm[i].port, SJA_Type, SJA_TYPE_GAMECTLR, TAG_DONE);
  1321.         }   }
  1322.  
  1323.         /* MAIN GAME LOOP ------------------------------------------------- */
  1324.  
  1325.         secondsleft = secondsperlevel;
  1326.         while (a == PLAYGAME)
  1327.         {   millielapsed += (delay / 1000);
  1328.             elapsed = millielapsed / 1000;
  1329.             r++;
  1330.             secondsleft = secondsperlevel - elapsed;
  1331.             if (secondsleft != oldsecondsleft)
  1332.             {   timeloop();
  1333.                 oldsecondsleft = secondsleft;
  1334.             }
  1335.             if (!turbo)
  1336.             {   TimerRqPtr->tr_node.io_Command  = TR_ADDREQUEST;
  1337.                 TimerRqPtr->tr_time.tv_secs     = 0;
  1338.                 TimerRqPtr->tr_time.tv_micro    = delay;
  1339.                 SendIO((struct IORequest *) TimerRqPtr);
  1340.                 evertimed = TRUE;
  1341.             }
  1342.             gameloop();
  1343.             if (CheckIO((struct IORequest *) TimerRqPtr))
  1344.             {   if (!clockdrawn)
  1345.                 {   draw(CLOCKICON, ICONY, CLOCK);
  1346.                 }
  1347.                 clockdrawn = TRUE;
  1348.             } else
  1349.             {   if (clockdrawn)
  1350.                 {   draw(CLOCKICON, ICONY, BLACKENED);
  1351.                 }
  1352.                 clockdrawn = FALSE;
  1353.             }
  1354.             WaitIO((struct IORequest *) TimerRqPtr);
  1355. }   }   }
  1356.  
  1357. EXPORT ABOOL anykey(ABOOL timeout)
  1358. {   ABOOL                done       = FALSE;
  1359.     SBYTE                count      = 0;
  1360.     UWORD                code, qual;
  1361.     ULONG                class;
  1362.     struct IntuiMessage* MsgPtr;
  1363.  
  1364.     clearkybd();
  1365.     Forbid();
  1366.     MainWindowPtr->Flags |= WFLG_RMBTRAP;
  1367.     Permit();
  1368.  
  1369.         while (!done && !firebutton())
  1370.         {   while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  1371.             {   class = MsgPtr->Class;
  1372.                 code  = MsgPtr->Code;
  1373.                 qual  = MsgPtr->Qualifier;
  1374.                 GT_ReplyIMsg(MsgPtr);
  1375.                 switch(class)
  1376.                 {
  1377.                 case IDCMP_RAWKEY:
  1378.                     if ((!(qual & IEQUALIFIER_REPEAT)) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
  1379.                     {   done = TRUE;
  1380.                         if (code == M)
  1381.                             toggle(M);
  1382.                         elif (code == F)
  1383.                             toggle(F);
  1384.                         elif (code == ESCAPE)
  1385.                         {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1386.                             {   if (verify())
  1387.                                 {   cleanexit(EXIT_SUCCESS);
  1388.                                 } else
  1389.                                 {   Forbid();
  1390.                                     MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  1391.                                     Permit();
  1392.                                     return(FALSE);
  1393.                     }   }   }   }
  1394.                 break;
  1395.                 case IDCMP_CLOSEWINDOW:
  1396.                     cleanexit(EXIT_SUCCESS);
  1397.                 break;
  1398.                 case IDCMP_ACTIVEWINDOW:
  1399.                     ignore = TRUE;
  1400.                 break;
  1401.                 case IDCMP_MOUSEBUTTONS:
  1402.                     if ((code == SELECTDOWN || code == MENUDOWN) && !(qual & IEQUALIFIER_REPEAT))
  1403.                         if (ignore)
  1404.                             ignore = FALSE;
  1405.                         else done = TRUE;
  1406.                 break;
  1407.                 case IDCMP_INTUITICKS:
  1408.                     if (timeout && ++count > PATIENCE)
  1409.                         done = TRUE;
  1410.                 break;
  1411.                 default:
  1412.                 break;
  1413.         }   }   }
  1414.  
  1415.     Forbid();
  1416.     MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  1417.     Permit();
  1418.     return TRUE;
  1419. }
  1420.  
  1421. EXPORT void celebrate(void)
  1422. {   ABOOL                done = FALSE;
  1423.     ULONG                class;
  1424.     UWORD                code, qual;
  1425.     struct IntuiMessage* MsgPtr;
  1426.     UBYTE                player;
  1427.  
  1428.     for (player = 0; player <= 3; player++)
  1429.         if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  1430.              worm[player].hiscore = worm[player].score;
  1431.     waitasec();
  1432.     clearkybd();
  1433.     while (!done && !firebutton)
  1434.     {   while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  1435.         {   class = MsgPtr->Class;
  1436.             code  = MsgPtr->Code;
  1437.             qual  = MsgPtr->Qualifier;
  1438.             GT_ReplyIMsg(MsgPtr);
  1439.             switch (class)
  1440.             {
  1441.             case IDCMP_RAWKEY:
  1442.                 if (code == ESCAPE)
  1443.                 {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1444.                     {   if (verify())
  1445.                         {   cleanexit(EXIT_SUCCESS);
  1446.                     }   }
  1447.                     else
  1448.                     {   done = TRUE;
  1449.                 }   }
  1450.                 elif (code == RETURN || code == ENTER || code == SPACEBAR)
  1451.                 {   done = TRUE;
  1452.                 } elif (code == M)
  1453.                 {   toggle(M);
  1454.                 } elif (code == F)
  1455.                 {   toggle(F);
  1456.                 }
  1457.             break;
  1458.             case IDCMP_MOUSEBUTTONS:
  1459.                 if (code == SELECTDOWN && !(qual & IEQUALIFIER_REPEAT))
  1460.                 {   if (ignore)
  1461.                     {   ignore = FALSE;
  1462.                     }
  1463.                     else
  1464.                     {   done = TRUE;
  1465.                 }   }
  1466.             break;
  1467.             case IDCMP_ACTIVEWINDOW:
  1468.                 ignore = TRUE;
  1469.             break;
  1470.             case IDCMP_CLOSEWINDOW:
  1471.                 cleanexit(EXIT_SUCCESS);
  1472.             break;
  1473.             default:
  1474.             break;
  1475.         }   }
  1476.         draw(rand() % (fieldx + 1), rand() % (fieldy + 1), rand() % LASTOBJECT);
  1477.     }
  1478.     a = GAMEOVER;
  1479. }
  1480.  
  1481. EXPORT void cleanexit(SLONG rc)
  1482. {   SBYTE i;
  1483.     BPTR  FileHandle;
  1484.  
  1485. if (TimerRqPtr && evertimed)
  1486.                         {       AbortIO((struct IORequest *) TimerRqPtr);
  1487.                                 WaitIO((struct IORequest *) TimerRqPtr);
  1488.                         }
  1489.                                 freefx();
  1490.                                 for (i = 0; i <= SAMPLES; i++)
  1491.                                     if (samp[i].base)
  1492.                                         FreeMem(samp[i].base, samp[i].size);
  1493. if (mode == MUSIC)   StopPlayer();
  1494.  
  1495. for (i = 0; i <= 6; i++)
  1496. {   if (SongPtr[i])
  1497.     {   UnLoadModule(SongPtr[i]);
  1498. }   }
  1499.  
  1500. if (MEDPlayerBase)    {     FreePlayer();
  1501.                          CloseLibrary((struct Library *) MEDPlayerBase);
  1502.                      }
  1503.  
  1504. if (ASLRqPtr)            FreeAslRequest(ASLRqPtr);
  1505. if (OldWindowPtr)        ProcessPtr->pr_WindowPtr = OldWindowPtr;
  1506.  
  1507. if (MainWindowPtr)    {   clearkybd();
  1508.                          ClearMenuStrip(MainWindowPtr);
  1509.                          CloseWindow(MainWindowPtr);
  1510.                      }
  1511.  
  1512. if (GListPtr)            FreeGadgets(GListPtr);
  1513. if (MenuPtr)            FreeMenus(MenuPtr);
  1514. if (VisualInfoPtr)   FreeVisualInfo(VisualInfoPtr);
  1515. if (ScreenPtr)       CloseScreen(ScreenPtr);
  1516. if (FontPtr)         CloseFont(FontPtr);
  1517. if (!TimerClosed)    CloseDevice((struct IORequest *) TimerRqPtr);
  1518. if (TimerRqPtr)      DeleteIORequest(TimerRqPtr);
  1519. if (TimerPortPtr)    DeleteMsgPort(TimerPortPtr);
  1520. if (TimeValPtr)      FreeMem(TimeValPtr, sizeof(struct timeval));
  1521. if (DiskFontBase)    CloseLibrary((struct Library *) DiskFontBase);
  1522. if (LowLevelBase)
  1523. {   for (i = 0; i <= 3; i++)
  1524.     {   SetJoyPortAttrs(worm[i].port, SJA_Reinitialize, TRUE, TAG_DONE);
  1525.     }
  1526.     CloseLibrary((struct Library *) LowLevelBase);
  1527. }
  1528. if (UtilityBase)                CloseLibrary((struct Library *) UtilityBase);
  1529. if (ASLBase)            CloseLibrary((struct Library *) ASLBase);
  1530. if (GadToolsBase)        CloseLibrary((struct Library *) GadToolsBase);
  1531. if (GfxBase)            CloseLibrary((struct Library *) GfxBase);
  1532. if (IconBase)            CloseLibrary((struct Library *) IconBase);
  1533. if (IntuitionBase)    {   OpenWorkBench();
  1534.                          CloseLibrary((struct Library *) IntuitionBase);
  1535.                      }
  1536.                      SetTaskPri((struct Task *) ProcessPtr, OldPri);
  1537. if (ArgsPtr)         FreeArgs(ArgsPtr);
  1538.  
  1539.     if (saveconfig)
  1540.     {   for (i = 0; i <= 3; i++)
  1541.         {   ConfigBuffer[i] = (SBYTE) worm[i].control;
  1542.         }
  1543.         ConfigBuffer[ 4] = (UBYTE)   (DisplayID     / 16777216);
  1544.         ConfigBuffer[ 5] = (UBYTE)  ((DisplayID     % 16777216) / 65536);
  1545.         ConfigBuffer[ 6] = (UBYTE) (((DisplayID     % 16777216) % 65536) / 256);
  1546.         ConfigBuffer[ 7] = (UBYTE) (((DisplayID     % 16777216) % 65536) % 256);
  1547.         ConfigBuffer[ 8] = (UBYTE)   (DisplayWidth  / 16777216);
  1548.         ConfigBuffer[ 9] = (UBYTE)  ((DisplayWidth  % 16777216) / 65536);
  1549.         ConfigBuffer[10] = (UBYTE) (((DisplayWidth  % 16777216) % 65536) / 256);
  1550.         ConfigBuffer[11] = (UBYTE) (((DisplayWidth  % 16777216) % 65536) % 256);
  1551.         ConfigBuffer[12] = (UBYTE)   (DisplayHeight / 16777216);
  1552.         ConfigBuffer[13] = (UBYTE)  ((DisplayHeight % 16777216) / 65536);
  1553.         ConfigBuffer[14] = (UBYTE) (((DisplayHeight % 16777216) % 65536) / 256);
  1554.         ConfigBuffer[15] = (UBYTE) (((DisplayHeight % 16777216) % 65536) % 256);
  1555.         ConfigBuffer[16] = (UBYTE)   (DisplayDepth  / 65536); // the DisplayDepth bytes are not used any more
  1556.         ConfigBuffer[17] = (UBYTE)   (DisplayDepth  % 65536);
  1557.         ConfigBuffer[18] = (UBYTE) randomflag;
  1558.         ConfigBuffer[19] = (UBYTE) icons;
  1559.         ConfigBuffer[20] = (UBYTE) anims;
  1560.         ConfigBuffer[21] = (UBYTE) titlebar;
  1561.         ConfigBuffer[22] = (UBYTE) engraved;
  1562.  
  1563.         if (FileHandle = Open("PROGDIR:WormWars.config", MODE_NEWFILE))
  1564.         {   Write(FileHandle, ConfigBuffer, CONFIGLENGTH);
  1565.             Close(FileHandle);
  1566.             // FileHandle = NULL;
  1567.     }   }
  1568.  
  1569.     exit(rc); /* End of program. */
  1570. }
  1571.  
  1572. EXPORT void clearkybd(void)
  1573. {   struct IntuiMessage* MsgPtr;
  1574.  
  1575.     while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  1576.         GT_ReplyIMsg(MsgPtr);
  1577. }
  1578.  
  1579. EXPORT void effect(SBYTE index)
  1580. {   AUTO    SBYTE i;
  1581.     AUTO    SBYTE ok            = -1;
  1582.     AUTO    ULONG oldestreceipt = (ULONG) -1L;
  1583.     PERSIST ULONG nextreceipt   = 1L;
  1584.  
  1585.     /* oldestreceipt = temporary variable for ascertaining oldest
  1586.                        sound still playing.
  1587.     nextreceipt = next unused receipt number (monotonically incrementing). */
  1588.  
  1589.     if (mode == FX)
  1590.     {   for (i = 0; i <= 3; i++)
  1591.         {   /* decide on a channel */
  1592.  
  1593.             if (ok == -1)
  1594.             {   if (!eversent[i])
  1595.                 {   ok = i;
  1596.                 } elif (CheckIO((struct IORequest *) AudioRqPtr[i]))
  1597.                 {   WaitIO((struct IORequest *) AudioRqPtr[i]);
  1598.                     ok = i;
  1599.         }   }   }
  1600.         if (ok == -1)
  1601.         {   for (i = 0; i <= 3; i++)
  1602.                 if (receipter[i] < oldestreceipt)
  1603.                 {   ok = i;
  1604.                     oldestreceipt = receipter[i];
  1605.                 }
  1606.             AbortIO((struct IORequest *) AudioRqPtr[ok]);
  1607.             WaitIO((struct IORequest *) AudioRqPtr[ok]);
  1608.         }
  1609.         eversent[ok] = TRUE;
  1610.         AudioRqPtr[ok]->ioa_Cycles              = 1;
  1611.         AudioRqPtr[ok]->ioa_Request.io_Command  = CMD_WRITE;
  1612.         AudioRqPtr[ok]->ioa_Request.io_Flags    = ADIOF_PERVOL;
  1613.         AudioRqPtr[ok]->ioa_Request.io_Unit     = (struct Unit *) (1 << ok);
  1614.         AudioRqPtr[ok]->ioa_Volume              = samp[index].volume;
  1615.         AudioRqPtr[ok]->ioa_Period              = (UWORD) samp[index].speed;
  1616.         AudioRqPtr[ok]->ioa_Request.io_Message.mn_ReplyPort
  1617.                                                 = AudioPortPtr[ok];
  1618.         AudioRqPtr[ok]->ioa_Data                = (UBYTE *) samp[index].base;
  1619.         AudioRqPtr[ok]->ioa_Length              = samp[index].length[samp[index].bank];
  1620.         BeginIO((struct IORequest *) AudioRqPtr[ok]);
  1621.         receipter[ok] = nextreceipt;
  1622. }   }
  1623.  
  1624. EXPORT void help(UBYTE type)
  1625. {   TEXT  title[10], tempstring[12];
  1626.     SWORD x, y;
  1627.     UBYTE i;
  1628.  
  1629.     effect(FXHELP);
  1630.     if (type == ORB)
  1631.     {   strcpy(title, "Creatures");
  1632.         x = 172;
  1633.         y = 28 + ((CREATUREHELPS + 1) * SQUAREY);
  1634.     } else
  1635.     {   strcpy(title, "Objects");
  1636.         x = 320;
  1637.         y = 32 + (LASTOBJECT * SQUAREY);
  1638.     }
  1639.     if (!(HelpWindowPtr = (struct Window *) OpenWindowTags(NULL,
  1640.     WA_Left,          (DisplayWidth  / 2) - (x / 2),
  1641.     WA_Top,           (DisplayHeight / 2) - (y / 2),
  1642.     WA_Width,         x,
  1643.     WA_Height,        y,
  1644.     WA_IDCMP,         IDCMP_CLOSEWINDOW |
  1645.                       IDCMP_RAWKEY |
  1646.                       IDCMP_MOUSEBUTTONS |
  1647.                       IDCMP_INTUITICKS,
  1648.     WA_Title,         title,
  1649.     WA_Gadgets,       NULL,
  1650.     WA_CustomScreen,  ScreenPtr,
  1651.     WA_DragBar,       TRUE,
  1652.     WA_CloseGadget,   TRUE,
  1653.     WA_NoCareRefresh, TRUE,
  1654.     WA_Activate,      TRUE,
  1655.     TAG_DONE)))
  1656.     {   say("Can't open help window!", RED);
  1657.         anykey(TRUE);
  1658.     } else
  1659.     {   SetAPen(HelpWindowPtr->RPort, WHITE);
  1660.         if (type == ORB)
  1661.         {   Move(HelpWindowPtr->RPort,  26 + (14 * FONTX), 20);
  1662.             Text(HelpWindowPtr->RPort, "Pts", 3);
  1663.             Move(HelpWindowPtr->RPort,  26, 22);
  1664.             Draw(HelpWindowPtr->RPort, 160, 22);
  1665.             for (i = 0; i <= CREATUREHELPS; i++)
  1666.             {   Image.ImageData = ImageData[creaturehelp[i].image];
  1667.                 DrawImage
  1668.                 (   HelpWindowPtr->RPort,
  1669.                     &Image,
  1670.                     10,
  1671.                     22 + (i * SQUAREY)
  1672.                 );
  1673.                 Move(HelpWindowPtr->RPort, 26           , 31 + (i * SQUAREY));
  1674.                 Text(HelpWindowPtr->RPort, creaturehelp[i].desc, strlen(creaturehelp[i].desc));
  1675.  
  1676.                 if
  1677.                 (   creaturehelp[i].image == LASTPROTECTOR
  1678.                  || creaturehelp[i].image == LASTHEAD
  1679.                  || creaturehelp[i].image == SLIME
  1680.                 )
  1681.                 {   stcl_d(tempstring, 0);
  1682.                 } else
  1683.                 {   assert(creaturehelp[i].image - FIRSTCREATURE >= FIRSTCREATURE && creaturehelp[i].image - FIRSTCREATURE <= LASTCREATURE);
  1684.                     stcl_d(tempstring, creatureinfo[creaturehelp[i].image - FIRSTCREATURE].score);
  1685.                 }
  1686.                 align(tempstring, 3, ' ');
  1687.                 Move(HelpWindowPtr->RPort, 26 + (14 * 8), 31 + (i * SQUAREY));
  1688.                 Text(HelpWindowPtr->RPort, tempstring, 3);
  1689.         }   }
  1690.         else
  1691.         {   assert(type == AFFIXER);
  1692.             for (i = 0; i <= LASTOBJECT; i++)
  1693.             {   Image.ImageData = ImageData[i];
  1694.                 Move(HelpWindowPtr->RPort, 26, 24 + (i * SQUAREY));
  1695.                 DrawImage
  1696.                 (   HelpWindowPtr->RPort,
  1697.                     &Image,
  1698.                     10,
  1699.                     15 + (i * SQUAREY)
  1700.                 );
  1701.                 Text(HelpWindowPtr->RPort, objectdesc[i], strlen(objectdesc[i]));
  1702.         }   }
  1703.         helploop(type);
  1704. }   }
  1705.  
  1706. EXPORT void helpabout(void)
  1707. {   SBYTE line;
  1708.     SLONG projectval;
  1709.     TEXT  projectstring[7], ks[5] = "    ", wb[5] = "    ";
  1710.     ULONG ksval = SysBase->LibNode.lib_Version,
  1711.           wbval = IconBase->lib_Version;
  1712.  
  1713.         effect(FXHELP);
  1714.     if (!(HelpWindowPtr = (struct Window *) OpenWindowTags(NULL,
  1715.         WA_Left,                        (DisplayWidth  / 2) - (ABOUTXPIXEL / 2),
  1716.         WA_Top,                         (DisplayHeight / 2) - (ABOUTYPIXEL / 2),
  1717.     WA_Width,            ABOUTXPIXEL,
  1718.     WA_Height,            ABOUTYPIXEL,
  1719.     WA_IDCMP,            IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
  1720.     WA_Title,            "About Worm Wars",
  1721.     WA_Gadgets,            NULL,
  1722.         WA_CustomScreen,  ScreenPtr,
  1723.         WA_DragBar,       TRUE,
  1724.         WA_CloseGadget,   TRUE,
  1725.         WA_NoCareRefresh, TRUE,
  1726.         WA_Activate,      TRUE,
  1727.     TAG_DONE)))
  1728.         {   say("Can't open About... window!", RED);
  1729.             anykey(TRUE);
  1730.     } else
  1731.         {   /* calculate project size */
  1732.  
  1733.             projectval =
  1734.               10                                 // header
  1735.             + ((HISCORES + 1) * HISCORESIZE)     // high scores
  1736.             + ((levels + 1) * (8 + (LEVELSIZE))) // level data
  1737.             + strlen(VERSION);                   // version string
  1738.  
  1739.             switch(ksval)
  1740.             {
  1741.                 case 37:
  1742.                     strcpy(ks, "2.04");
  1743.                 break;
  1744.                 case 38:
  1745.                     strcpy(ks, "2.1 ");
  1746.                 break;
  1747.                 case 39:
  1748.                     strcpy(ks, "3.0 ");
  1749.                 break;
  1750.                 case 40:
  1751.                 case 41:
  1752.                 case 42:
  1753.                 case 43:
  1754.                     strcpy(ks, "3.1 ");
  1755.                 break;
  1756.                 case 44:
  1757.                     strcpy(ks, "3.5 ");
  1758.                 break;
  1759.                 case 45:
  1760.                     strcpy(ks, "3.9 ");
  1761.                 break;
  1762.                 default:
  1763.                     strcpy(ks, "4.0+");
  1764.                 break;
  1765.                 }
  1766.  
  1767.         switch(wbval)
  1768.         {
  1769.         case 37:
  1770.             strcpy(wb, "2.04");
  1771.         break;
  1772.         case 38:
  1773.             strcpy(wb, "2.1 ");
  1774.         break;
  1775.         case 39:
  1776.             strcpy(wb, "3.0 ");
  1777.         break;
  1778.         case 40:
  1779.         case 41:
  1780.         case 42:
  1781.         case 43:
  1782.             strcpy(wb, "3.1 ");
  1783.         break;
  1784.         case 44:
  1785.             strcpy(wb, "3.5 ");
  1786.         break;
  1787.         case 45:
  1788.             strcpy(wb, "3.9 ");
  1789.         break;
  1790.         default:
  1791.             strcpy(wb, "4.0+");
  1792.         break;
  1793.         }
  1794.  
  1795.         SetAPen(HelpWindowPtr->RPort, worm[rand() % 4].colour);
  1796.         RectFill(HelpWindowPtr->RPort, 8, 13, ABOUTXPIXEL - 11, ABOUTYPIXEL - 6);
  1797.         SetAPen(HelpWindowPtr->RPort, ABOUTSHADOW);
  1798.         Move(HelpWindowPtr->RPort, 7, ABOUTYPIXEL - 5);
  1799.         Draw(HelpWindowPtr->RPort, 7, 12);
  1800.         Draw(HelpWindowPtr->RPort, ABOUTXPIXEL - 10, 12);
  1801.         SetAPen(HelpWindowPtr->RPort, ABOUTSHINE);
  1802.         Draw(HelpWindowPtr->RPort, ABOUTXPIXEL - 10, ABOUTYPIXEL - 5);
  1803.         Draw(HelpWindowPtr->RPort, 8, ABOUTYPIXEL - 5);
  1804.         SetAPen(HelpWindowPtr->RPort, BLACK);
  1805.         SetDrMd(HelpWindowPtr->RPort, JAM1);
  1806.         for (line = 0; line <= ABOUTLINES; line++)
  1807.         {   Move(HelpWindowPtr->RPort, about[line].x, about[line].y);
  1808.             Text(HelpWindowPtr->RPort, about[line].text, (SBYTE) strlen(about[line].text));
  1809.         }
  1810.         stcl_d(projectstring, projectval);
  1811.         align(projectstring, 6, ' ');
  1812.         Move(HelpWindowPtr->RPort, PROJECTX, PROJECTY);
  1813.         Text(HelpWindowPtr->RPort, projectstring, 6);
  1814.         Move(HelpWindowPtr->RPort, KICKSTARTX, KICKSTARTY);
  1815.         Text(HelpWindowPtr->RPort, ks, 4);
  1816.         Move(HelpWindowPtr->RPort, WORKBENCHX, WORKBENCHY);
  1817.         Text(HelpWindowPtr->RPort, wb, 4);
  1818.  
  1819.         DrawBevelBox(HelpWindowPtr->RPort, 16, 20, 44 + 4, 38 + 4, GT_VisualInfo, VisualInfoPtr, GTBB_Recessed, TRUE, TAG_END);
  1820.         drawabout();
  1821.  
  1822.         helploop(NOSQUARE);
  1823. }   }
  1824.  
  1825. EXPORT void helploop(UBYTE type)
  1826. {   ABOOL                done = FALSE;
  1827.     UBYTE                objx, objy;
  1828.     UWORD                code, qual;
  1829.     SWORD                mousex, mousey;
  1830.     SBYTE                birdframe = -1, birddir = 1;
  1831.     ULONG                class;
  1832.     struct IntuiMessage* MsgPtr;
  1833.  
  1834.     while(!done)
  1835.     {   Wait(1L << HelpWindowPtr->UserPort->mp_SigBit);
  1836.         while (MsgPtr = (struct IntuiMessage *) GetMsg(HelpWindowPtr->UserPort))
  1837.         {   class  = MsgPtr->Class;
  1838.             code   = MsgPtr->Code;
  1839.             qual   = MsgPtr->Qualifier;
  1840.             mousex = MsgPtr->MouseX;
  1841.             mousey = MsgPtr->MouseY;
  1842.             ReplyMsg((struct Message *) MsgPtr);
  1843.             switch(class)
  1844.             {
  1845.             case IDCMP_INTUITICKS:
  1846.                 if (type == ORB && anims)
  1847.                 {   birdframe += birddir;
  1848.                     Image.ImageData = ImageData[birdframes[birdframe]];
  1849.                     DrawImage
  1850.                     (   HelpWindowPtr->RPort,
  1851.                         &Image,
  1852.                         10,
  1853.                         46
  1854.                     );
  1855.                     if (birdframe == 0)
  1856.                     {   birddir = 1;
  1857.                     } elif (birdframe == 4)
  1858.                     {   birddir = -1;
  1859.                 }   }
  1860.             break;
  1861.             case IDCMP_CLOSEWINDOW:
  1862.                 done = TRUE;
  1863.             break;
  1864.             case IDCMP_RAWKEY:
  1865.                 if (code == SPACEBAR || code == RETURN || code == ENTER || code == HELP)
  1866.                     done = TRUE;
  1867.                 elif (code == ESCAPE)
  1868.                 {   if (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  1869.                     {   if (verify())
  1870.                         {   CloseWindow(HelpWindowPtr);
  1871.                             cleanexit(EXIT_SUCCESS);
  1872.                    }   }
  1873.                    else done = TRUE;
  1874.                 }
  1875.             break;
  1876.             case IDCMP_MOUSEBUTTONS:
  1877.                 if (a == FIELDEDIT && type == AFFIXER)
  1878.                 {   objx = (mousex - 10) / 328; // which column
  1879.                     objy = (mousey - 13) / 10;  // which row
  1880.                     if ((objx == 0 || objx == 1) && (objy >= 0 && objy <= LASTOBJECT / 2))
  1881.                     {   if (objx)
  1882.                             setbrush(objy + 1 + (LASTOBJECT / 2));
  1883.                         else setbrush(objy);
  1884.                         done = TRUE;
  1885.                 }   }
  1886.             break;
  1887.             default:
  1888.             break;
  1889.     }   }   }
  1890.     CloseWindow(HelpWindowPtr);
  1891.     HelpWindowPtr = NULL;
  1892.     clearkybd();
  1893. }
  1894.  
  1895. EXPORT void filedelete(void)
  1896. {   TEXT newpathname[255], temp1[81];
  1897.  
  1898.     if (AslRequestTags(ASLRqPtr, ASL_Hail, "Delete Levelset", ASL_FuncFlags, FILF_PATGAD | FILF_SAVE, TAG_DONE) && *(ASLRqPtr->rf_File) != 0)
  1899.     {   strcpy(newpathname, ASLRqPtr->rf_Dir);
  1900.         AddPart(newpathname, ASLRqPtr->rf_File, 254);
  1901.         if (DeleteFile(newpathname))
  1902.         {   strcpy(temp1, "Deleted ");
  1903.             strcat(temp1, newpathname);
  1904.             strcat(temp1, ".");
  1905.         } else
  1906.         {   strcpy(temp1, "Couldn't delete ");
  1907.             strcat(temp1, newpathname);
  1908.             strcat(temp1, "!");
  1909.         }
  1910.         say(temp1, WHITE);
  1911. }   }
  1912.  
  1913. EXPORT void fileopen(ABOOL revert)
  1914. {   TEXT temp1[81],
  1915.          temp2[3],
  1916.          newpathname[255];
  1917.  
  1918.     strcpy(temp1, "Opened ");
  1919.     strcpy(newpathname, pathname);
  1920.     if (revert || (AslRequestTags(ASLRqPtr, ASL_Hail, "Open Levelset", ASL_FuncFlags, FILF_PATGAD, TAG_DONE) && *(ASLRqPtr->rf_File)))
  1921.     {   if (!revert)
  1922.         {   strcpy(newpathname, ASLRqPtr->rf_Dir);
  1923.             AddPart(newpathname, ASLRqPtr->rf_File, 254);
  1924.         }
  1925.         if (!loadfields(newpathname))
  1926.         {   strcpy(pathname, newpathname);
  1927.             strcat(temp1, pathname);
  1928.             strcat(temp1, " (");
  1929.             stci_d(temp2, levels);
  1930.             strcat(temp1, temp2);
  1931.             strcat(temp1, " levels).");
  1932.             say(temp1, WHITE);
  1933.             if (a == FIELDEDIT)
  1934.                 turborender();
  1935.             else hiscores();
  1936.         } else
  1937.         {   strcpy(temp1, "Couldn't open ");
  1938.             strcat(temp1, newpathname);
  1939.             strcat(temp1, "!");
  1940.             say(temp1, WHITE);
  1941.     }   }
  1942.     if (a == GAMEOVER)
  1943.         anykey(TRUE);
  1944. }
  1945.  
  1946. EXPORT void filesaveas(ABOOL flag)
  1947. {    ABOOL    cont = TRUE;
  1948.     TEXT    newpathname[255], temp1[SAYLIMIT + 1], temp2[3];
  1949.         struct DiskObject* InfoHandle;
  1950.  
  1951.     /* flag is TRUE for 'save as...', FALSE for 'save'. */
  1952.  
  1953.     strcpy(newpathname, pathname);
  1954.     if (flag)
  1955.         if (AslRequestTags(ASLRqPtr, ASL_Hail, "Save Levelset", ASL_FuncFlags, FILF_PATGAD | FILF_SAVE, TAG_DONE) && *(ASLRqPtr->rf_File) != 0)
  1956.         {   strcpy(newpathname, ASLRqPtr->rf_Dir);
  1957.             AddPart(newpathname, ASLRqPtr->rf_File, 254);
  1958.         } else cont = FALSE;
  1959.     if (cont)
  1960.     {   strcpy(temp1, "Saving ");
  1961.     strcat(temp1, newpathname);
  1962.     strcat(temp1, "...");
  1963.     say(temp1, WHITE);
  1964.     if (savefields(newpathname))
  1965.         {   strcpy(pathname, newpathname);
  1966.             if (icons)
  1967.             {   InfoHandle = GetDiskObjectNew(DEFAULTSET);
  1968.                 InfoHandle->do_CurrentX = NO_ICON_POSITION;
  1969.                 InfoHandle->do_CurrentY = NO_ICON_POSITION;
  1970.                 if (!PutDiskObject(pathname, InfoHandle))
  1971.                 {   say("Couldn't write .info file!", RED);
  1972.                     anykey(TRUE);
  1973.             }   }
  1974.             strcpy(temp1, "Saved ");
  1975.             strcat(temp1, pathname);
  1976.             strcat(temp1, " (");
  1977.             stci_d(temp2, levels);
  1978.             strcat(temp1, temp2);
  1979.             strcat(temp1, " levels).");
  1980.         } else
  1981.         {   strcpy(temp1, "Couldn't save ");
  1982.             strcat(temp1, newpathname);
  1983.             strcat(temp1, "!");
  1984.         }
  1985.         say(temp1, WHITE);
  1986.         if (a == GAMEOVER)
  1987.             anykey(TRUE);
  1988. }   }
  1989.  
  1990. EXPORT void gameinput(void)
  1991. {   ABOOL                allowed = TRUE,
  1992.                          done;
  1993.     UWORD                code,
  1994.                          qual = 0; // to avoid spurious compiler warnings
  1995.     ULONG                class;
  1996.     struct IntuiMessage* MsgPtr;
  1997.     SBYTE                keyplayer, i;
  1998.     UBYTE                which;
  1999.  
  2000.     for (which = 0; which <= NUMKEYS; which++)
  2001.         key[which].down = FALSE;
  2002.  
  2003.     /* keyboard */
  2004.  
  2005.     while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  2006.     {   class = MsgPtr->Class;
  2007.         code  = MsgPtr->Code;
  2008.         qual  = MsgPtr->Qualifier;
  2009.         ReplyMsg((struct Message *) MsgPtr);
  2010.         if (class == IDCMP_RAWKEY && (!(qual & IEQUALIFIER_REPEAT)))
  2011.         {   if (code < KEYUP)
  2012.             {   switch(code)
  2013.             {
  2014.             case M:
  2015.                 toggle(M);
  2016.             break;
  2017.                 case F:
  2018.                     toggle(F);
  2019.                 break;
  2020.                 case KEY_T:
  2021.                     // check whether any human worms are playing
  2022.                     for (i = 0; i <= 3; i++)
  2023.                     {   if
  2024.                         (   worm[i].control != AMIGA
  2025.                          && worm[i].control != NONE
  2026.                          && worm[i].lives
  2027.                         )
  2028.                         {   allowed = FALSE;
  2029.                             break;
  2030.                     }   }
  2031.                     if (allowed)
  2032.                     {   if (turbo)
  2033.                         {   turbo = FALSE;
  2034.                         } else
  2035.                         {   turbo = TRUE;
  2036.                             draw(CLOCKICON, ICONY, CLOCK);
  2037.                     }   }
  2038.                 break;
  2039.                 case P:
  2040.                     clearkybd();
  2041.                     say("Paused...press P to unpause", WHITE);
  2042.                     done = FALSE;
  2043.                     while (!done)
  2044.                     {   Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  2045.                         while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  2046.                         {   class = MsgPtr->Class;
  2047.                             code  = MsgPtr->Code;
  2048.                             qual  = MsgPtr->Qualifier;
  2049.                             ReplyMsg((struct Message *) MsgPtr);
  2050.                         if (class == IDCMP_RAWKEY && (!(qual & IEQUALIFIER_REPEAT)))
  2051.                         {   if (code == ESCAPE)
  2052.                             {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2053.                                 {   if (verify())
  2054.                                         cleanexit(EXIT_SUCCESS);
  2055.                                     } else
  2056.                                     {   a = GAMEOVER;
  2057.                                         done = TRUE;
  2058.                                         worm[0].lives = worm[1].lives = worm[2].lives = worm[3].lives = 0;
  2059.                                 }   }
  2060.                                 elif (code == M)
  2061.                                     toggle(M);
  2062.                                 elif (code == F)
  2063.                                     toggle(F);
  2064.                                 elif (code == P)
  2065.                                 {   say("Unpaused", WHITE);
  2066.                                     done = TRUE;
  2067.                     }   }   }   }
  2068.                 break;
  2069.                 case ESCAPE:
  2070.                     if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2071.                     {   if (verify())
  2072.                             cleanexit(EXIT_SUCCESS);
  2073.                     } else
  2074.                     {   a = GAMEOVER;
  2075.                         worm[0].lives = worm[1].lives = worm[2].lives = worm[3].lives = 0;
  2076.                     }
  2077.                 break;
  2078.                 default:
  2079.                    for (which = 0; which <= NUMKEYS; which++)
  2080.                        if (code == key[which].scancode)
  2081.                            key[which].down = TRUE;
  2082.                 break;
  2083.         }   }   }
  2084.         elif (class == IDCMP_CLOSEWINDOW)
  2085.             cleanexit(EXIT_SUCCESS);
  2086.         elif (class == IDCMP_REFRESHWINDOW)
  2087.         {   GT_BeginRefresh(MainWindowPtr);
  2088.             GT_EndRefresh(MainWindowPtr, TRUE);
  2089.     }   }
  2090.  
  2091.     for (which = 0; which <= NUMKEYS; which++)
  2092.     {   if (key[which].down)
  2093.         {   if (key[which].special == ONEHUMAN)
  2094.             {   if
  2095.                 (   (worm[0].control == KEYBOARD && worm[1].control != KEYBOARD)
  2096.                 )
  2097.                 {   wormqueue(0, key[which].deltax, key[which].deltay);
  2098.                 } elif
  2099.                 (   (worm[1].control == KEYBOARD && worm[0].control != KEYBOARD)
  2100.                 )
  2101.                 {   wormqueue(1, key[which].deltax, key[which].deltay);
  2102.             }   }
  2103.             elif (key[which].special == MOVE || key[which].special == AMMO)
  2104.             {   if (worm[key[which].player].control == KEYBOARD)
  2105.                 {   keyplayer = key[which].player;
  2106.                 } elif
  2107.                 (   key[which].player == 1
  2108.                  && (worm[0].control == KEYBOARD && worm[1].control != KEYBOARD)
  2109.                 )
  2110.                 {   keyplayer = 0;
  2111.                 } elif
  2112.                 (   key[which].player == 0
  2113.                  && (worm[1].control == KEYBOARD && worm[0].control != KEYBOARD)
  2114.                 )
  2115.                 {   keyplayer = 1;
  2116.                 } else keyplayer = -1;
  2117.                 if (keyplayer != -1)
  2118.                 {   wormqueue(keyplayer, key[which].deltax, key[which].deltay);
  2119.             }   }
  2120.             else
  2121.             {   assert(key[which].special == TRAINER);
  2122.                 if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2123.                 {   train(key[which].scancode, TRUE);
  2124.                 } else
  2125.                 {   train(key[which].scancode, FALSE);
  2126. }   }   }   }   }
  2127.  
  2128. EXPORT void hiscores(void)
  2129. {   SBYTE which;
  2130.     TEXT  tempstring[NAMELENGTH + 1];
  2131.  
  2132.     /* render hiscores
  2133.  
  2134.     #################################################### # = shadow
  2135.     #   #   #   #                      #     #         % % = shine
  2136.     #   #   #   #                      #     #         %
  2137.     #   #   #   #                      #     #         %
  2138.     #   #   #   #                      #     #         %
  2139.     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
  2140.  
  2141.     hiframe = 0;
  2142.     SetDrMd(MainWindowPtr->RPort, JAM1);
  2143.     for (which = 0; which <= HISCORES; which++)
  2144.     {   if (hiscore[which].player == -1)
  2145.             SetAPen(MainWindowPtr->RPort, LIGHTGREY);
  2146.         else SetAPen(MainWindowPtr->RPort, worm[hiscore[which].player].colour);
  2147.         RectFill
  2148.         (   MainWindowPtr->RPort,
  2149.             CENTREXPIXEL - 216,
  2150.             YSTART + 134 + (which * HISCOREDISTANCE),
  2151.             CENTREXPIXEL + 216,
  2152.             YSTART + 143 + (which * HISCOREDISTANCE)
  2153.         );
  2154.     if (hiscore[which].player == 0)
  2155.             SetAPen(MainWindowPtr->RPort, DARKGREEN);
  2156.         elif (hiscore[which].player == 1)
  2157.             SetAPen(MainWindowPtr->RPort, DARKRED);
  2158.         elif (hiscore[which].player == 2)
  2159.             SetAPen(MainWindowPtr->RPort, DARKBLUE);
  2160.         elif (hiscore[which].player == 3)
  2161.             SetAPen(MainWindowPtr->RPort, DARKYELLOW);
  2162.     else SetAPen(MainWindowPtr->RPort, DARKGREY);
  2163.         Move(MainWindowPtr->RPort, CENTREXPIXEL - 217, YSTART + 144 + (which * HISCOREDISTANCE));
  2164.         Draw(MainWindowPtr->RPort, CENTREXPIXEL - 217, YSTART + 133 + (which * HISCOREDISTANCE));
  2165.         Draw(MainWindowPtr->RPort, CENTREXPIXEL + 217, YSTART + 133 + (which * HISCOREDISTANCE));
  2166.  
  2167.     if (hiscore[which].player != -1)
  2168.         {   /* divider bars */
  2169.  
  2170.             Move(MainWindowPtr->RPort, CENTREXPIXEL - 193, YSTART + 133 + (which * HISCOREDISTANCE));
  2171.             Draw(MainWindowPtr->RPort, CENTREXPIXEL - 193, YSTART + 143 + (which * HISCOREDISTANCE));
  2172.             Move(MainWindowPtr->RPort, CENTREXPIXEL - 121, YSTART + 133 + (which * HISCOREDISTANCE));
  2173.             Draw(MainWindowPtr->RPort, CENTREXPIXEL - 121, YSTART + 143 + (which * HISCOREDISTANCE));
  2174.             Move(MainWindowPtr->RPort, CENTREXPIXEL -  85, YSTART + 133 + (which * HISCOREDISTANCE));
  2175.             Draw(MainWindowPtr->RPort, CENTREXPIXEL -  85, YSTART + 143 + (which * HISCOREDISTANCE));
  2176.             Move(MainWindowPtr->RPort, CENTREXPIXEL +  92, YSTART + 133 + (which * HISCOREDISTANCE));
  2177.             Draw(MainWindowPtr->RPort, CENTREXPIXEL +  92, YSTART + 143 + (which * HISCOREDISTANCE));
  2178.             Move(MainWindowPtr->RPort, CENTREXPIXEL + 142, YSTART + 133 + (which * HISCOREDISTANCE));
  2179.             Draw(MainWindowPtr->RPort, CENTREXPIXEL + 142, YSTART + 143 + (which * HISCOREDISTANCE));
  2180.     }
  2181.     SetAPen(MainWindowPtr->RPort, WHITE);
  2182.         Move(MainWindowPtr->RPort, CENTREXPIXEL - 217, YSTART + 144 + (which * HISCOREDISTANCE));
  2183.         Draw(MainWindowPtr->RPort, CENTREXPIXEL + 217, YSTART + 144 + (which * HISCOREDISTANCE));
  2184.         Draw(MainWindowPtr->RPort, CENTREXPIXEL + 217, YSTART + 134 + (which * HISCOREDISTANCE));
  2185.     SetAPen(MainWindowPtr->RPort, BLACK);
  2186.  
  2187.     if (hiscore[which].player != -1)
  2188.         {   stci_d(tempstring, which + 1);
  2189.             tempstring[1] = '.';
  2190.             Move(MainWindowPtr->RPort, CENTREXPIXEL - 214, YSTART + 141 + (which * HISCOREDISTANCE));
  2191.             Text(MainWindowPtr->RPort, tempstring, 2);
  2192.             stci_d(tempstring, hiscore[which].score);
  2193.             align(tempstring, 7, ' ');
  2194.             Move(MainWindowPtr->RPort, CENTREXPIXEL - 182, YSTART + 141 + (which * HISCOREDISTANCE));
  2195.             Text(MainWindowPtr->RPort, tempstring, 7);
  2196.             if (hiscore[which].level == -1)
  2197.             {   strcpy(tempstring, "All");
  2198.             } else
  2199.             {   stci_d(tempstring, hiscore[which].level);
  2200.                 align(tempstring, 3, ' ');
  2201.             }
  2202.  
  2203.             Move(MainWindowPtr->RPort, CENTREXPIXEL - 114, YSTART + 141 + (which * HISCOREDISTANCE));
  2204.             Text(MainWindowPtr->RPort, tempstring, 3);
  2205.             Move(MainWindowPtr->RPort, CENTREXPIXEL -  79, YSTART + 141 + (which * HISCOREDISTANCE));
  2206.             Text(MainWindowPtr->RPort, hiscore[which].name, strlen(hiscore[which].name));
  2207.             Move(MainWindowPtr->RPort, CENTREXPIXEL +  98, YSTART + 141 + (which * HISCOREDISTANCE));
  2208.             Text(MainWindowPtr->RPort, hiscore[which].time, strlen(hiscore[which].time));
  2209.             Move(MainWindowPtr->RPort, CENTREXPIXEL + 148, YSTART + 141 + (which * HISCOREDISTANCE));
  2210.             Text(MainWindowPtr->RPort, hiscore[which].date, strlen(hiscore[which].date));
  2211.  
  2212.             Image.ImageData = ImageData[missileframes[hiscore[which].player][0]];
  2213.             DrawImage(MainWindowPtr->RPort, &Image, CENTREXPIXEL + 220, YSTART + 133 + (which * HISCOREDISTANCE));
  2214.     }   }
  2215.     SetDrMd(MainWindowPtr->RPort, JAM2);
  2216. }
  2217.  
  2218. EXPORT void hiscorenames(void)
  2219. {   ULONG                class;
  2220.     ABOOL                done;
  2221.     SBYTE                which;
  2222.     struct IntuiMessage* MsgPtr;
  2223.  
  2224.     for (which = 0; which <= HISCORES; which++)
  2225.     {   if (hiscore[which].fresh)
  2226.         {   GT_SetGadgetAttrs(StringGadgetPtr[which], MainWindowPtr, NULL, GA_Disabled, FALSE, GTST_String, worm[hiscore[which].player].name, TAG_DONE);
  2227.             ActivateGadget(StringGadgetPtr[which], MainWindowPtr, NULL);
  2228.             done = FALSE;
  2229.             while (!done)
  2230.             {   while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  2231.                 {   class = MsgPtr->Class;
  2232.                     GT_ReplyIMsg(MsgPtr);
  2233.                     if (class == IDCMP_GADGETUP)
  2234.                     {   done = TRUE;
  2235.                     } elif (class == IDCMP_MOUSEBUTTONS)
  2236.                     {   ActivateGadget(StringGadgetPtr[which], MainWindowPtr, NULL);
  2237.                     } elif (class == IDCMP_REFRESHWINDOW)
  2238.                     {   GT_BeginRefresh(MainWindowPtr);
  2239.                         GT_EndRefresh(MainWindowPtr, TRUE);
  2240.             }   }   }
  2241.             GT_SetGadgetAttrs(StringGadgetPtr[which], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2242.             effect(FXAPPLAUSE);
  2243.             strcpy(hiscore[which].name, ((struct StringInfo *) (StringGadgetPtr[which]->SpecialInfo))->Buffer);
  2244.             if (hiscore[which].name[0] >= 'a' && hiscore[which].name[0] <= 'z')
  2245.             {   hiscore[which].name[0] -= 32;
  2246.             }
  2247.             strcpy(worm[hiscore[which].player].name, hiscore[which].name);
  2248.             hiscore[which].fresh = FALSE;
  2249.             hiscores();
  2250. }   }   }
  2251.  
  2252. EXPORT void resettime(void)
  2253. {   millielapsed = 0;
  2254.  
  2255.     GetSysTime(TimeValPtr);
  2256.     srand((UWORD) TimeValPtr->tv_micro);
  2257. }
  2258.  
  2259. EXPORT void systemrundown(SBYTE player, UBYTE multiply)
  2260. {   FLAG                 done = FALSE;
  2261.     TEXT                 tempstring[6];
  2262.     SBYTE                i;
  2263.     UWORD                code, qual;
  2264.     ULONG                class;
  2265.     struct IntuiMessage* MsgPtr;
  2266.  
  2267.     PERSIST TEXT runstring[5][RUNSTRINGLENGTH + 1] =
  2268.     {" Level Bonus:   ## x #### =",
  2269.      "Number Bonus:   ## x #### =",
  2270.      "  Time Bonus: #:## x #### =",
  2271.      "   Dim Bonus:   ## x #### =",
  2272.      "  Glow Bonus:   ## x #### ="};
  2273.  
  2274.     DrawBevelBox(MainWindowPtr->RPort, RUNDOWNX, RUNDOWNY, 304, 66, GT_VisualInfo, VisualInfoPtr, TAG_END);
  2275.     SetAPen(MainWindowPtr->RPort, BLACK);
  2276.     RectFill
  2277.     (   MainWindowPtr->RPort,
  2278.         RUNDOWNX + 1,
  2279.         RUNDOWNY + 1,
  2280.         RUNDOWNX + 302,
  2281.         RUNDOWNY + 64
  2282.     );
  2283.     SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2284.  
  2285.     Image.ImageData = ImageData[TREASURE];
  2286.     DrawImage(MainWindowPtr->RPort, &Image, RUNDOWNX + 8, RUNDOWNY + 3);
  2287.     if (worm[player].numbers == 0)
  2288.     {   Image.ImageData = ImageData[FIRSTPAIN + player];
  2289.     } else
  2290.     {   Image.ImageData = ImageData[FIRSTNUMBER + worm[player].numbers - 1];
  2291.     }
  2292.     DrawImage(MainWindowPtr->RPort, &Image, RUNDOWNX + 8, RUNDOWNY + 3 +  SQUAREY     );
  2293.     Image.ImageData = ImageData[CLOCK];
  2294.     DrawImage(MainWindowPtr->RPort, &Image, RUNDOWNX + 8, RUNDOWNY + 3 + (SQUAREY * 2));
  2295.     Image.ImageData = ImageData[FIRSTTAIL + player];
  2296.     DrawImage(MainWindowPtr->RPort, &Image, RUNDOWNX + 8, RUNDOWNY + 3 + (SQUAREY * 3));
  2297.     Image.ImageData = ImageData[FIRSTGLOW + player];
  2298.     DrawImage(MainWindowPtr->RPort, &Image, RUNDOWNX + 8, RUNDOWNY + 3 + (SQUAREY * 4));
  2299.  
  2300.     for (i = 0; i <= 4; i++)
  2301.     {   Move(MainWindowPtr->RPort, RUNDOWNX + RUNDOWNX_1ST, RUNDOWNY + RUNDOWNY_2ND + (SQUAREY * i));
  2302.         Text(MainWindowPtr->RPort, runstring[i], RUNSTRINGLENGTH);
  2303.         if (i == 2)
  2304.         {   tempstring[0] = 48 + (quantity[2][0] / 60);
  2305.             tempstring[1] = ':';
  2306.             tempstring[2] = 48 + ((quantity[2][0] % 60) / 10);
  2307.             tempstring[3] = 48 + ((quantity[2][0] % 60) % 10);
  2308.         } else
  2309.         {   stci_d(tempstring, quantity[i][0]);
  2310.             align(tempstring, 4, ' ');
  2311.         }
  2312.         Move(MainWindowPtr->RPort, RUNDOWNX + RUNDOWNX_2ND, RUNDOWNY + RUNDOWNY_2ND + (SQUAREY * i));
  2313.         Text(MainWindowPtr->RPort, tempstring, 4);
  2314.         stci_d(tempstring, quantity[i][1]);
  2315.         align(tempstring, 4, ' ');
  2316.         Move(MainWindowPtr->RPort, RUNDOWNX + RUNDOWNX_3RD, RUNDOWNY + RUNDOWNY_2ND + (SQUAREY * i));
  2317.         Text(MainWindowPtr->RPort, tempstring, 4);
  2318.     }
  2319.  
  2320.     while (!done)
  2321.     {   while (MsgPtr = (struct IntuiMessage *) GetMsg(MainWindowPtr->UserPort))
  2322.         {   class  = MsgPtr->Class;
  2323.         code   = MsgPtr->Code;
  2324.         qual   = MsgPtr->Qualifier;
  2325.         ReplyMsg((struct Message *) MsgPtr);
  2326.             if (class == IDCMP_RAWKEY && (!(qual & IEQUALIFIER_REPEAT)) && code < KEYUP)
  2327.             {   done = TRUE;
  2328.         }   }
  2329.  
  2330.         if (done)
  2331.     {   wormscore
  2332.             (   player,
  2333.                 (quantity[0][2] + quantity[1][2] + quantity[2][2] + quantity[3][2] + quantity[4][2]) / multiply
  2334.             );
  2335.             quantity[0][2] =
  2336.             quantity[1][2] =
  2337.             quantity[2][2] =
  2338.             quantity[3][2] =
  2339.             quantity[4][2] = 0;
  2340.         }
  2341.  
  2342.         done = TRUE;
  2343.         for (i = 0; i <= 4; i++)
  2344.         {   stci_d(tempstring, quantity[i][2]);
  2345.             align(tempstring, 5, ' ');
  2346.             Move(MainWindowPtr->RPort, RUNDOWNX + RUNDOWNX_4TH, RUNDOWNY + RUNDOWNY_2ND + (SQUAREY * i));
  2347.             Text(MainWindowPtr->RPort, tempstring, 5);
  2348.  
  2349.             if (quantity[i][2])
  2350.             {   if (quantity[i][2] >= multiply * 2)
  2351.                 {   quantity[i][2] -= multiply * 2;
  2352.                     wormscore(player, 2);
  2353.                 } else
  2354.                 {   quantity[i][2] -= multiply;
  2355.                     wormscore(player, 1);
  2356.                 }
  2357.                 done = FALSE;
  2358.         }   }
  2359.         effect(FXCLICK);
  2360. }   }
  2361.  
  2362. EXPORT void say(STRPTR sentence, COLOUR colour)
  2363. {   SWORD length  = (SBYTE) strlen(sentence),
  2364.           centrex;
  2365.  
  2366.     centrex = STARTXPIXEL + ((ENDXPIXEL - STARTXPIXEL) / 2);
  2367.  
  2368.     /* truncate text */
  2369.     if (length > SAYLIMIT)
  2370.     {   *(sentence + SAYLIMIT) = 0;
  2371.         length = SAYLIMIT;
  2372.     }
  2373.  
  2374.     /* clear areas to left and right of text, respectively */
  2375.     SetAPen(MainWindowPtr->RPort, BLACK);
  2376.     RectFill
  2377.     (   MainWindowPtr->RPort,
  2378.         STARTXPIXEL,
  2379.         TBSIZE + 4,
  2380.         centrex - (length * FONTX / 2),
  2381.         TBSIZE + 15
  2382.     );
  2383.     RectFill
  2384.     (   MainWindowPtr->RPort,
  2385.         centrex + (length * FONTX / 2) + 1,
  2386.         TBSIZE + 4,
  2387.         ENDXPIXEL,
  2388.         TBSIZE + 15
  2389.     );
  2390.  
  2391.     /* render shadow text */
  2392.     SetAPen(MainWindowPtr->RPort, MEDIUMGREY);
  2393.     Move(MainWindowPtr->RPort, centrex - (length * FONTX / 2) + 1, TBSIZE + FONTY + 3);
  2394.     Text(MainWindowPtr->RPort, sentence, length);
  2395.  
  2396.     /* render actual text */
  2397.     SetDrMd(MainWindowPtr->RPort, JAM1);
  2398.     SetAPen(MainWindowPtr->RPort, colour);
  2399.     Move(MainWindowPtr->RPort, centrex - (length * FONTX / 2), TBSIZE + FONTY + 3);
  2400.     Text(MainWindowPtr->RPort, sentence, length);
  2401.     SetDrMd(MainWindowPtr->RPort, JAM2);
  2402. }
  2403.  
  2404. EXPORT void printstat(SBYTE player, SBYTE theline)
  2405. {   Move
  2406.     (   MainWindowPtr->RPort,
  2407.         FONTX * 3,
  2408.         STARTYPIXEL + (player * SQUAREX * 10) + 8 + (theline * SQUAREY)
  2409.     );
  2410.     Text(MainWindowPtr->RPort, stattext, 7);
  2411. }
  2412.  
  2413. EXPORT void stopfx(void)
  2414. {   SBYTE i;
  2415.  
  2416.     for (i = 0; i <= 3; i++)
  2417.     {   if (eversent[i] && AudioRqPtr[i])
  2418.         {   AbortIO((struct IORequest *) AudioRqPtr[i]);
  2419.             WaitIO((struct IORequest *) AudioRqPtr[i]);
  2420. }   }   }
  2421.  
  2422. EXPORT void titlescreen(void)
  2423. {   SBYTE                player, i;
  2424.     ULONG                class;
  2425.     UWORD                code, qual;
  2426.     TEXT                 tempstring[8];
  2427.     struct IntuiMessage* MsgPtr;
  2428.     struct Gadget*       WhichGadgetPtr;
  2429.     struct MenuItem*     ItemPtr;
  2430.  
  2431.     Forbid();
  2432.     MainWindowPtr->Flags &= ~WFLG_RMBTRAP;
  2433.     Permit();
  2434.     clearscreen();
  2435.  
  2436.     SetDrMd(MainWindowPtr->RPort, JAM2);
  2437.     drawlogo();
  2438.  
  2439.     SetMenuStrip(MainWindowPtr, MenuPtr);
  2440.     for (player = 0; player <= 3; player++)
  2441.     {   GT_SetGadgetAttrs(CycleGadgetPtr[player], MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2442.     }
  2443.     GT_SetGadgetAttrs(ShuffleGadgetPtr, MainWindowPtr, NULL, GA_Disabled, FALSE, TAG_DONE);
  2444.     SetDrMd(MainWindowPtr->RPort, JAM1);
  2445.  
  2446.     strcpy(tempstring, "Worm  :");
  2447.     for (player = 0; player <= 3; player++)
  2448.     {   tempstring[5] = '1' + player;
  2449.  
  2450.         SetAPen(MainWindowPtr->RPort, BLACK);
  2451.         Move(MainWindowPtr->RPort, CENTREXPIXEL - (12 * FONTX) + 1, YSTART + 263 + (player * (FONTY + 5)));
  2452.         Text(MainWindowPtr->RPort, tempstring, 7);
  2453.         Move(MainWindowPtr->RPort, CENTREXPIXEL - ( 7 * FONTX) + 1, YSTART + 264 + (player * (FONTY + 5)));
  2454.         Text(MainWindowPtr->RPort, "_", 1);
  2455.  
  2456.         SetAPen(MainWindowPtr->RPort, worm[player].colour);
  2457.         Move(MainWindowPtr->RPort, CENTREXPIXEL - (12 * FONTX), YSTART + 262 + (player * (FONTY + 5)));
  2458.         Text(MainWindowPtr->RPort, tempstring, 7);
  2459.         Move(MainWindowPtr->RPort, CENTREXPIXEL - ( 7 * FONTX), YSTART + 263 + (player * (FONTY + 5)));
  2460.         Text(MainWindowPtr->RPort, "_", 1);
  2461.     }
  2462.  
  2463.     SetAPen(MainWindowPtr->RPort, BLACK);
  2464.     Move(MainWindowPtr->RPort, CENTREXPIXEL - (10 * FONTX) + 1, YSTART + 328);
  2465.     Text(MainWindowPtr->RPort, "Shuffle Levels?", 15);
  2466.     Move(MainWindowPtr->RPort, CENTREXPIXEL - (10 * FONTX) + 1, YSTART + 329);
  2467.     Text(MainWindowPtr->RPort, "_", 1);
  2468.     Move(MainWindowPtr->RPort, CENTREXPIXEL - (18 * FONTX / 2) + 1, YSTART + 225);
  2469.     Text(MainWindowPtr->RPort,   "RETURN: Start Game",   18);
  2470.     Move(MainWindowPtr->RPort, CENTREXPIXEL - (22 * FONTX / 2) + 1, YSTART + 235);
  2471.     Text(MainWindowPtr->RPort, "Spacebar: Level Editor", 22);
  2472.  
  2473.     SetAPen(MainWindowPtr->RPort, WHITE);
  2474.     Move(MainWindowPtr->RPort, CENTREXPIXEL - (10 * FONTX), YSTART + 327);
  2475.     Text(MainWindowPtr->RPort, "Shuffle Levels?", 15);
  2476.     Move(MainWindowPtr->RPort, CENTREXPIXEL - (10 * FONTX), YSTART + 328);
  2477.     Text(MainWindowPtr->RPort, "_", 1);
  2478.     Move(MainWindowPtr->RPort, CENTREXPIXEL - (18 * FONTX / 2), YSTART + 224);
  2479.     Text(MainWindowPtr->RPort,   "RETURN: Start Game",   18);
  2480.     Move(MainWindowPtr->RPort, CENTREXPIXEL - (22 * FONTX / 2), YSTART + 234);
  2481.     Text(MainWindowPtr->RPort, "Spacebar: Level Editor", 22);
  2482.  
  2483.     clearkybd();
  2484.     hiscores();
  2485.     hiscorenames();
  2486.  
  2487.     playsong(0);
  2488.  
  2489.     do
  2490.     {   Wait(1L << MainWindowPtr->UserPort->mp_SigBit);
  2491.         while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
  2492.         {   WhichGadgetPtr = (struct Gadget *) MsgPtr->IAddress;
  2493.             class = MsgPtr->Class;
  2494.             code  = MsgPtr->Code;
  2495.             qual  = MsgPtr->Qualifier;
  2496.             GT_ReplyIMsg(MsgPtr);
  2497.             switch (class)
  2498.             {
  2499.             case IDCMP_RAWKEY:
  2500.                 if (!(qual & IEQUALIFIER_REPEAT))
  2501.                 {   switch (code)
  2502.                     {
  2503.                     case F:
  2504.                         toggle(F);
  2505.                     break;
  2506.                     case M:
  2507.                         toggle(M);
  2508.                     break;
  2509.                     case SPACEBAR:
  2510.                         a = FIELDEDIT;
  2511.                     break;
  2512.                     case F1:
  2513.                     case ALPHAONE:
  2514.                     case NUMERICONE:
  2515.                         effect(FXCLICK);
  2516.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2517.                         {   if (--worm[0].control < 0)
  2518.                                 worm[0].control = 4;
  2519.                         } else
  2520.                         {   if (++worm[0].control > 4)
  2521.                                 worm[0].control = 0;
  2522.                         }
  2523.                         GT_SetGadgetAttrs(CycleGadgetPtr[0], MainWindowPtr, NULL, GTCY_Active, worm[0].control, TAG_DONE);
  2524.                     break;
  2525.                     case F2:
  2526.                     case ALPHATWO:
  2527.                     case NUMERICTWO:
  2528.                         effect(FXCLICK);
  2529.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2530.                         {   if (--worm[1].control < 0)
  2531.                                 worm[1].control = 4;
  2532.                         } else
  2533.                         {   if (++worm[1].control > 4)
  2534.                                 worm[1].control = 0;
  2535.                         }
  2536.                         GT_SetGadgetAttrs(CycleGadgetPtr[1], MainWindowPtr, NULL, GTCY_Active, worm[1].control, TAG_DONE);
  2537.                     break;
  2538.                     case F3:
  2539.                     case ALPHATHREE:
  2540.                     case NUMERICTHREE:
  2541.                         effect(FXCLICK);
  2542.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2543.                         {   if (worm[2].control > 0)
  2544.                             {   worm[2].control--;
  2545.                             } else worm[2].control = 3;
  2546.                         } else
  2547.                         {   if (worm[2].control < 3)
  2548.                             {   worm[2].control++;
  2549.                             } else worm[2].control = 0;
  2550.                         }
  2551.                         GT_SetGadgetAttrs(CycleGadgetPtr[2], MainWindowPtr, NULL, GTCY_Active, worm[2].control, TAG_DONE);
  2552.                     break;
  2553.                     case F4:
  2554.                     case ALPHAFOUR:
  2555.                     case NUMERICFOUR:
  2556.                         effect(FXCLICK);
  2557.                         if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2558.                         {   if (--worm[3].control < 0)
  2559.                                 worm[3].control = 3;
  2560.                         } else
  2561.                         {   if (++worm[3].control > 3)
  2562.                                 worm[3].control = 0;
  2563.                         }
  2564.                         GT_SetGadgetAttrs(CycleGadgetPtr[3], MainWindowPtr, NULL, GTCY_Active, worm[3].control, TAG_DONE);
  2565.                     break;
  2566.                     case RETURN:
  2567.                     case ENTER:
  2568.                         a = PLAYGAME;
  2569.                     break;
  2570.                     case S:
  2571.                         randomflag = !randomflag;
  2572.                         GT_SetGadgetAttrs(ShuffleGadgetPtr, MainWindowPtr, NULL, GTCB_Checked, randomflag, TAG_DONE);
  2573.                     break;
  2574.                     case ESCAPE:
  2575.                         if (verify())
  2576.                             cleanexit(EXIT_SUCCESS);
  2577.                     break;
  2578.                     case HELP:
  2579.                         helpabout();
  2580.                     break;
  2581.                     default:
  2582.                     break;
  2583.                 }   }
  2584.             break;
  2585.             case IDCMP_MENUPICK:
  2586.                 while (code != MENUNULL)
  2587.                 {   ItemPtr = ItemAddress(MenuPtr, code);
  2588.  
  2589.                     switch (MENUNUM(code))
  2590.                     {
  2591.                     case MN_PROJECT:
  2592.                         switch (ITEMNUM(code))
  2593.                         {
  2594.                         case IN_NEW:
  2595.                             newfields();
  2596.                             say("New done.", WHITE);
  2597.                         break;
  2598.                         case IN_OPEN:
  2599.                             fileopen(FALSE);
  2600.                         break;
  2601.                         case IN_REVERT:
  2602.                             fileopen(TRUE);
  2603.                         break;
  2604.                         case IN_SAVE:
  2605.                             filesaveas(FALSE);
  2606.                         break;
  2607.                         case IN_SAVEAS:
  2608.                             filesaveas(TRUE);
  2609.                         break;
  2610.                         case IN_PROJECTDELETE:
  2611.                             filedelete();
  2612.                         break;
  2613.                         case IN_QUIT:
  2614.                             if (verify())
  2615.                                 cleanexit(EXIT_SUCCESS);
  2616.                         break;
  2617.                         default:
  2618.                         break;
  2619.                         }
  2620.                     break;
  2621.                     case MN_SETTINGS:
  2622.                         switch(ITEMNUM(code))
  2623.                         {
  2624.                         case IN_ANIMATIONS:
  2625.                             if (ItemPtr->Flags & CHECKED)
  2626.                             {   anims = TRUE;
  2627.                             } else
  2628.                             {   anims = FALSE;
  2629.                             }
  2630.                         break;
  2631.                         case IN_CREATEICONS:
  2632.                             if (ItemPtr->Flags & CHECKED)
  2633.                             {   icons = TRUE;
  2634.                             } else
  2635.                             {   icons = FALSE;
  2636.                             }
  2637.                         break;
  2638.                         case IN_ENGRAVEDSQUARES:
  2639.                             if (ItemPtr->Flags & CHECKED)
  2640.                             {   engraved = TRUE;
  2641.                             } else
  2642.                             {   engraved = FALSE;
  2643.                             }
  2644.                         break;
  2645.                         case IN_SHOWTITLEBAR:
  2646.                             if (ItemPtr->Flags & CHECKED)
  2647.                             {   titlebar = TRUE;
  2648.                             } else
  2649.                             {   titlebar = FALSE;
  2650.                             }
  2651.                             ShowTitle(ScreenPtr, titlebar);
  2652.                         break;
  2653.                         default:
  2654.                         break;
  2655.                         }
  2656.                     break;
  2657.                     case MN_HELP:
  2658.                         switch(ITEMNUM(code))
  2659.                         {
  2660.                         case IN_ABOUT:
  2661.                             helpabout();
  2662.                         break;
  2663.                         case IN_CREATURES:
  2664.                             help(ORB);
  2665.                         break;
  2666.                         case IN_OBJECTS:
  2667.                             help(AFFIXER);
  2668.                         break;
  2669.                         default:
  2670.                         break;
  2671.                         }
  2672.                     break;
  2673.                     default:
  2674.                     break;
  2675.                     }
  2676.                     code = ItemPtr->NextSelect;
  2677.                 }
  2678.             break;
  2679.             case IDCMP_MOUSEBUTTONS:
  2680.                 if (code == SELECTDOWN)
  2681.                 {   if (ignore)
  2682.                     {   ignore = FALSE;
  2683.                     } else
  2684.                     {   a = PLAYGAME;
  2685.                 }   }
  2686.             break;
  2687.             case IDCMP_REFRESHWINDOW:
  2688.                 GT_BeginRefresh(MainWindowPtr);
  2689.                 GT_EndRefresh(MainWindowPtr, TRUE);
  2690.             break;
  2691.             case IDCMP_GADGETUP:
  2692.                 if (WhichGadgetPtr == ShuffleGadgetPtr)
  2693.                 {   randomflag = !randomflag;
  2694.                 } else
  2695.                 {   for (player = 0; player <= 3; player++)
  2696.                     {   if (WhichGadgetPtr == CycleGadgetPtr[player])
  2697.                         {   worm[player].control = code;
  2698.                             break;
  2699.                 }   }   }
  2700.             break;
  2701.             case IDCMP_ACTIVEWINDOW:
  2702.                 ignore = TRUE;
  2703.             break;
  2704.             case IDCMP_CLOSEWINDOW:
  2705.                 cleanexit(EXIT_SUCCESS);
  2706.             break;
  2707.             case IDCMP_INTUITICKS:
  2708.                 if (anims)
  2709.                 {   drawboing();
  2710.                     // cyclecolours();
  2711.  
  2712.                     for (i = 0; i <= HISCORES; i++)
  2713.                     {   if (hiscore[i].player != -1)
  2714.                         {   Image.ImageData = ImageData[missileframes[hiscore[i].player][hiframe]];
  2715.                             DrawImage(MainWindowPtr->RPort, &Image, CENTREXPIXEL + 220, YSTART + 133 + (i * HISCOREDISTANCE));
  2716.                             if (++hiframe > MISSILEFRAMES)
  2717.                             {   hiframe = 0;
  2718.                 }   }   }   }
  2719.                 if (firebutton())
  2720.                 {   a = PLAYGAME;
  2721.                 }
  2722.             break;
  2723.             default:
  2724.                 ; /* IDCMP_MENUVERIFY */
  2725.             break;
  2726.         }   }
  2727.  
  2728.         if (a == PLAYGAME)
  2729.         {   if (worm[0].control == NONE && worm[1].control == NONE && worm[2].control == NONE && worm[3].control == NONE)
  2730.             {   say("No worms active!", WHITE);
  2731.                 anykey(TRUE);
  2732.                 a = GAMEOVER;
  2733.             } elif
  2734.             (   !LowLevelBase &&
  2735.                 (worm[0].control == GAMEPAD
  2736.               || worm[1].control == GAMEPAD
  2737.               || worm[2].control == GAMEPAD
  2738.               || worm[3].control == GAMEPAD
  2739.             )   )
  2740.             {   say("Need OS3.1+ for gamepad!", WHITE);
  2741.                 anykey(TRUE);
  2742.                 a = GAMEOVER;
  2743.     }   }   }
  2744.     while (a == GAMEOVER);
  2745.  
  2746.     for (player = 0; player <= 3; player++)
  2747.     {   GT_SetGadgetAttrs(CycleGadgetPtr[player], MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2748.     }
  2749.     GT_SetGadgetAttrs(ShuffleGadgetPtr, MainWindowPtr, NULL, GA_Disabled, TRUE, TAG_DONE);
  2750.  
  2751.     if (a == FIELDEDIT)
  2752.     {   fieldedit();
  2753.     } else
  2754.     {   assert(a == PLAYGAME);
  2755.         turbo = FALSE;
  2756.         newgame();
  2757.         clearkybd();
  2758.         Forbid();
  2759.         MainWindowPtr->Flags |= WFLG_RMBTRAP;
  2760.         Permit();
  2761. }   }
  2762.  
  2763. EXPORT void toggle(SBYTE key)
  2764. {   PERSIST ABOOL songstarted = FALSE;
  2765.  
  2766.     switch(key)
  2767.     {
  2768.     case F:
  2769.         if (mode == FX) /* F in FX mode: no sound */
  2770.         {   freefx();
  2771.             mode = FALSE;
  2772.             draw(MUSICICON, ICONY, BLACKENED);
  2773.         } else if (fxable != FAILED) /* F otherwise: change to FX mode */
  2774.         {   if (mode == MUSIC) /* stop any music that is playing */
  2775.             {   StopPlayer();
  2776.                 FreePlayer();
  2777.             }
  2778.             if (fxable == DEFER) /* load samples if needed */
  2779.                 loadthefx();
  2780.             if (fxable == SUCCEEDED) /* if we have samples in memory */
  2781.             {   if (beginfx())
  2782.                 {   mode = FX;
  2783.                     effect(FXGET_RAIN);
  2784.                     draw(MUSICICON, ICONY, FX);
  2785.         }   }   }
  2786.     break;
  2787.     case M:
  2788.         if (mode == MUSIC) /* M in MUSIC mode: no sound */
  2789.         {   StopPlayer();
  2790.             FreePlayer();
  2791.             mode = FALSE;
  2792.             draw(MUSICICON, ICONY, BLACKENED);
  2793.         } else if (musicable != FAILED) /* M otherwise: change to music mode */
  2794.         {   if (mode == FX) /* stop any samples that are playing */
  2795.                 freefx();
  2796.             /* Of course, these statements are ordered in this
  2797.             way for a reason, so don't change it. :-) */
  2798.             if (musicable == DEFER)
  2799.                 loadthemusic();
  2800.             if (musicable == SUCCEEDED)
  2801.             {   if (GetPlayer(0))
  2802.                 {   say("No channels for music!", RED);
  2803.                     anykey(TRUE);
  2804.                     mode = FALSE;
  2805.                     draw(MUSICICON, ICONY, BLACKENED);
  2806.                 } else
  2807.                 {   if (songstarted)
  2808.                         ContModule(SongPtr[song]);
  2809.                     else
  2810.                     {   PlayModule(SongPtr[song]);
  2811.                         songstarted = TRUE;
  2812.                     }
  2813.                     mode = MUSIC;
  2814.                     draw(MUSICICON, ICONY, MUSIC);
  2815.         }   }   }
  2816.     break;
  2817.     default:
  2818.         flash(2);
  2819.         assert(0);
  2820.     break;
  2821. }   }
  2822.  
  2823. EXPORT ABOOL verify(void)
  2824. {   if (modified && (EasyRequest(MainWindowPtr, &EasyStruct, NULL) == 0))
  2825.         return FALSE;
  2826.     else return TRUE;
  2827. }
  2828.  
  2829. EXPORT void waitasec(void)
  2830. {   Delay(50);
  2831. }
  2832.  
  2833. EXPORT void systemsetup(void)
  2834. {   worm[0].control = NONE;
  2835.     worm[1].control = KEYBOARD;
  2836.     worm[2].control = NONE;
  2837.     worm[3].control = AMIGA;
  2838. }
  2839.  
  2840. EXPORT ABOOL ZOpen(STRPTR fieldname, ABOOL write)
  2841. {   if (!write)
  2842.         if (FilePtr = Open(fieldname, MODE_OLDFILE))
  2843.             return TRUE;
  2844.         else return FALSE;
  2845.     else
  2846.         if (FilePtr = Open(fieldname, MODE_NEWFILE))
  2847.             return TRUE;
  2848.         else return FALSE;
  2849. }
  2850. EXPORT ABOOL ZRead(STRPTR IOBuffer, ULONG length)
  2851. {   if (Read(FilePtr, IOBuffer, length) == length)
  2852.         return TRUE;
  2853.     else return FALSE;
  2854. }
  2855. EXPORT ABOOL ZWrite(STRPTR IOBuffer, ULONG length)
  2856. {   if (Write(FilePtr, IOBuffer, length) == length)
  2857.         return TRUE;
  2858.     else return FALSE;
  2859. }
  2860. EXPORT ABOOL ZClose(void)
  2861. {   if (Close(FilePtr))
  2862.     {   FilePtr = NULL;
  2863.         return TRUE;
  2864.     } else
  2865.     {   /* "If Close() returns DOSFALSE, the user has already cancelled an
  2866.         error requester and the function has already freed the FileHandle
  2867.         (and even marked it so any attempt to close it again will bring up
  2868.         the "Software Failure" requester). Therefore FilePtr should be set
  2869.         to zero in any case." - Jilles Tjoelker. */
  2870.  
  2871.         FilePtr = NULL;
  2872.         return FALSE;
  2873. }   }
  2874.  
  2875. EXPORT void timing(void)
  2876. {   ;
  2877. }
  2878.  
  2879. EXPORT void clearscreen(void)
  2880. {   SBYTE i, j;
  2881.  
  2882.     if (DisplayDepth >= DEPTH5)
  2883.     {   drawbackground();
  2884.     } else
  2885.     {   SetAPen(MainWindowPtr->RPort, BLACK);
  2886.         RectFill(MainWindowPtr->RPort, 0, 0, ENTIREXPIXEL, ENTIREYPIXEL);
  2887.     }
  2888.  
  2889.     if (mode == MUSIC)
  2890.         draw(MUSICICON, ICONY, MUSIC);
  2891.     elif (mode == FX)
  2892.         draw(MUSICICON, ICONY, FX);
  2893.     else draw(MUSICICON, ICONY, BLACKENED);
  2894.     draw(CLOCKICON, ICONY, BLACKENED);
  2895.     clockdrawn = FALSE;
  2896.  
  2897.     if (a != FIELDEDIT && !first)
  2898.     {   for (i = 0; i <= 3; i++)
  2899.         {   if (worm[i].control != NONE)
  2900.             {   draw(-6, (i * 10)    , BONUS);
  2901.                 draw(-6, (i * 10) + 1, MINIHEALER);
  2902.                 draw(-6, (i * 10) + 2, BRAKES);
  2903.                 draw(-6, (i * 10) + 3, AMMO);
  2904.                 draw(-6, (i * 10) + 4, POWER);
  2905.                 for (j = 0; j <= LASTOBJECT; j++)
  2906.                 {   icon(i, j);
  2907.     }   }   }   }
  2908.  
  2909.     first = FALSE;
  2910. }
  2911.  
  2912. EXPORT void datestamp(void)
  2913. {   ULONG            seconds, micros;
  2914.     struct ClockData Date;
  2915.     TEXT             temp[5];
  2916.  
  2917.     CurrentTime(&seconds, µs);
  2918.     Amiga2Date(seconds, &Date);
  2919.     stci_d(times, Date.hour); /* hh */
  2920.     align(times, 2, ' ');
  2921.     times[2] = ':';           /* hh: */
  2922.     times[3] = 0;
  2923.     stci_d(temp, Date.min);
  2924.     align(temp, 2, '0');
  2925.     temp[2] = 0;
  2926.     strcat(times, temp);      /* hh:mm */
  2927.  
  2928.     stci_d(date, Date.mday);  /* dd */
  2929.     align(date, 2, ' ');
  2930.     date[2] = '/';
  2931.     date[3] = 0;              /* dd/ */
  2932.     stci_d(temp, Date.month);
  2933.     align(temp, 2, ' ');
  2934.     temp[2] = 0;
  2935.     strcat(date, temp);       /* dd/mm */
  2936.     strcat(date, "/");        /* dd/mm/ */
  2937.     stci_d(temp, Date.year);
  2938.     temp[0] = temp[2];
  2939.     temp[1] = temp[3];
  2940.     temp[2] = 0;
  2941.     strcat(date, temp);       /* dd/mm/yy */
  2942. }
  2943.  
  2944. EXPORT void turborender(void)
  2945. {   UBYTE random = rand() % 3;
  2946.     SBYTE x, y;
  2947.  
  2948.     if (a != PLAYGAME || (!level) || !(randomflag))
  2949.         sourcelevel = level;
  2950.  
  2951.     if (a == FIELDEDIT)
  2952.     {   for (x = 0; x <= MINFIELDX; x++)
  2953.         {   for (y = 0; y <= MINFIELDY; y++)
  2954.             {   fedraw(x, y, board[level][x][y]);
  2955.     }   }   }
  2956.     else
  2957.     {   changefield();
  2958.         switch(random)
  2959.         {
  2960.         case 0:
  2961.             for (x = 0; x <= fieldx; x += 2)
  2962.             {   for (y = 0; y <= fieldy; y += 2)
  2963.                 {   draw(x, y, field[x][y]);
  2964.                 }
  2965.                 if (x < fieldx)
  2966.                 {   for (y = 1; y <= fieldy; y += 2)
  2967.                     {   draw(x + 1, y, field[x + 1][y]);
  2968.             }   }   }
  2969.             for (x = 0; x <= fieldx; x += 2)
  2970.             {   for (y = 1; y <= fieldy; y += 2)
  2971.                 {   draw(x, y, field[x][y]);
  2972.                 }
  2973.                 if (x < fieldx)
  2974.                 {   for (y = 0; y <= fieldy; y += 2)
  2975.                     {   draw(x + 1, y, field[x + 1][y]);
  2976.             }   }   }
  2977.         break;
  2978.         case 1:
  2979.             for (y = 0; y <= fieldy; y += 2)
  2980.             {   for (x = 0; x <= fieldx; x++)
  2981.                 {   draw(x, y, field[x][y]);
  2982.             }   }
  2983.             for (y = 1; y <= fieldy; y += 2)
  2984.             {   for (x = 0; x <= fieldx; x++)
  2985.                 {   draw(x, y, field[x][y]);
  2986.             }   }
  2987.         break;
  2988.         case 2:
  2989.             for (y = 0; y <= fieldy; y += 2)
  2990.             {   for (x = 0; x <= fieldx; x++)
  2991.                 {   draw(x, y, field[x][y]);
  2992.                 }
  2993.                 if (y < fieldy)
  2994.                 {   for (x = fieldx; x >= 0; x--)
  2995.                     {   draw(x, y + 1, field[x][y + 1]);
  2996.             }   }   }
  2997.         break;
  2998.         default:
  2999.             assert(0);
  3000.         break;
  3001.     }   }
  3002.  
  3003.     if (a == FIELDEDIT)
  3004.     {   fedraw(startx[sourcelevel], starty[sourcelevel], START);
  3005.         dot();
  3006.     } else
  3007.     {   for (y = 0; y <= fieldy; y++)
  3008.         {   draw(ARROWX, y, BLACKARROW);
  3009.     }   }
  3010.  
  3011.     SetAPen(MainWindowPtr->RPort, MEDIUMGREY);
  3012.     if (a == FIELDEDIT)
  3013.     {   Move(MainWindowPtr->RPort, STARTXPIXEL + ( LEFTGAP * SQUAREX)    ,   ENDYPIXEL - (BOTTOMGAP * SQUAREY) + 1);
  3014.         Draw(MainWindowPtr->RPort,   ENDXPIXEL - (RIGHTGAP * SQUAREX)    ,   ENDYPIXEL - (BOTTOMGAP * SQUAREY) + 1);
  3015.         Move(MainWindowPtr->RPort,   ENDXPIXEL - (RIGHTGAP * SQUAREX) + 1, STARTYPIXEL + (   TOPGAP * SQUAREY)    );
  3016.         Draw(MainWindowPtr->RPort,   ENDXPIXEL - (RIGHTGAP * SQUAREX) + 1,   ENDYPIXEL - (BOTTOMGAP * SQUAREY) + 1);
  3017.         SetAPen(MainWindowPtr->RPort, BLACK);
  3018.         Move(MainWindowPtr->RPort, STARTXPIXEL + ( LEFTGAP * SQUAREX) + 1,   ENDYPIXEL - (BOTTOMGAP * SQUAREY) + 2);
  3019.         Draw(MainWindowPtr->RPort,   ENDXPIXEL - (RIGHTGAP * SQUAREX) + 1,   ENDYPIXEL - (BOTTOMGAP * SQUAREY) + 2);
  3020.         Move(MainWindowPtr->RPort,   ENDXPIXEL - (RIGHTGAP * SQUAREX) + 2, STARTYPIXEL + (   TOPGAP * SQUAREY) + 1);
  3021.         Draw(MainWindowPtr->RPort,   ENDXPIXEL - (RIGHTGAP * SQUAREX) + 2,   ENDYPIXEL - (BOTTOMGAP * SQUAREY) + 2);
  3022.     } else
  3023.     {   Move(MainWindowPtr->RPort, STARTXPIXEL    ,   ENDYPIXEL + 1);
  3024.         Draw(MainWindowPtr->RPort,   ENDXPIXEL    ,   ENDYPIXEL + 1);
  3025.         Move(MainWindowPtr->RPort,   ENDXPIXEL + 1, STARTYPIXEL    );
  3026.         Draw(MainWindowPtr->RPort,   ENDXPIXEL + 1,   ENDYPIXEL + 1);
  3027.         SetAPen(MainWindowPtr->RPort, BLACK);
  3028.         Move(MainWindowPtr->RPort, STARTXPIXEL + 1,   ENDYPIXEL + 2);
  3029.         Draw(MainWindowPtr->RPort,   ENDXPIXEL + 1,   ENDYPIXEL + 2);
  3030.         Move(MainWindowPtr->RPort,   ENDXPIXEL + 2, STARTYPIXEL + 1);
  3031.         Draw(MainWindowPtr->RPort,   ENDXPIXEL + 2,   ENDYPIXEL + 2);
  3032. }   }
  3033.  
  3034. EXPORT void ReadAdapterJoystick(UBYTE unit)
  3035. {   AUTO    UBYTE firebit, addroffset, snapshot;
  3036.     AUTO    SBYTE xx = 0, yy = 0;
  3037.     AUTO    ABOOL fire           = FALSE;
  3038.     PERSIST UBYTE oldsnapshot[2] = {0, 0};
  3039.     PERSIST ABOOL oldfire[2]     = {0, 0};
  3040.     PERSIST UBYTE *fireaddrPtr,
  3041.                   *moveaddrPtr;
  3042.  
  3043.     fireaddrPtr = (UBYTE *) 0xBFD000;
  3044.     moveaddrPtr = (UBYTE *) 0xBFE101;
  3045.  
  3046. /*  Those pointers could easily be auto or constant or whatever; they
  3047.     never change.
  3048.  
  3049.     bit 7 of $bfe101 is right of joystick '4'
  3050.     bit 6 of $bfe101 is left  of joystick '4'
  3051.     bit 5 of $bfe101 is down  of joystick '4'
  3052.     bit 4 of $bfe101 is up    of joystick '4'
  3053.     bit 3 of $bfe101 is right of joystick '3'
  3054.     bit 2 of $bfe101 is left  of joystick '3'
  3055.     bit 1 of $bfe101 is down  of joystick '3'
  3056.     bit 0 of $bfe101 is up    of joystick '3'
  3057.  
  3058.     bit 2 of $bfd000 is fire  of joystick '3'
  3059.     bit 0 of $bfd000 is fire  of joystick '4'
  3060.  
  3061.     unit: number of the unit (2 = '3', 3 = '4') */
  3062.  
  3063.     if (unit == 2)
  3064.     {   firebit = 2;
  3065.         addroffset = 0;
  3066.     } else
  3067.     {   assert(unit == 3);
  3068.         firebit = 0;
  3069.         addroffset = 4;
  3070.     }
  3071.  
  3072.     if (worm[unit].control == JOYSTICK && worm[unit].lives)
  3073.     {   if ((*fireaddrPtr) & (1 << firebit))
  3074.             fire = TRUE;
  3075.  
  3076.         snapshot = *moveaddrPtr; // we cache this address in the snapshot
  3077.                                  // variable, so that joystick reading is an
  3078.                                  // atomic operation
  3079.         if (snapshot & (1 << (addroffset + 3)))
  3080.             xx = 1;
  3081.         elif (snapshot & (1 << (addroffset + 2)))
  3082.             xx = -1;
  3083.         if (snapshot & (1 << (addroffset + 1)))
  3084.             yy = 1;
  3085.         elif (snapshot & (1 <<  addroffset     ))
  3086.             yy = -1;
  3087.  
  3088.         if (oldsnapshot[unit - 2] != snapshot || oldfire[unit - 2] != fire)
  3089.         {   if (fire)
  3090.                 wormqueue(unit, 0, 0);
  3091.             else
  3092.                 wormqueue(unit, xx, yy);
  3093.         }
  3094.         oldsnapshot[unit - 2] = snapshot;
  3095.         oldfire[unit - 2]     = fire;
  3096. }   }
  3097.  
  3098. EXPORT void ReadStandardJoystick(ULONG port)
  3099. {   AUTO    UBYTE PortState[2];
  3100.     AUTO    ABOOL fire            = FALSE;
  3101.     AUTO    SBYTE xx              = 0,
  3102.                   yy              = 0,
  3103.                   player;
  3104.     PERSIST UBYTE OldPortState[2] = {0, 0};
  3105.  
  3106.     if (port == 1)
  3107.     {   player = 2; // blue worm
  3108.     } else
  3109.     {   assert(port == 0);
  3110.         player = 3; // yellow worm
  3111.     }
  3112.     if (worm[player].control == JOYSTICK && worm[player].lives)
  3113.     {   PortState[port] = ReadJoystick(port);
  3114.         if (PortState[port] != OldPortState[port])
  3115.         {   if (PortState[port] & JOYUP)
  3116.                 yy = -1;
  3117.             elif (PortState[port] & JOYDOWN)
  3118.                 yy = 1;
  3119.             if (PortState[port] & JOYLEFT)
  3120.                 xx = -1;
  3121.             elif (PortState[port] & JOYRIGHT)
  3122.                 xx = 1;
  3123.             if (PortState[port] & JOYFIRE1)
  3124.             {   fire = TRUE;
  3125.             }
  3126.  
  3127.             // this doesn't work perfectly?
  3128.             if (PortState[port] != 0 && (worm[player].brakes || xx == 0 || yy == 0))
  3129.             // if joystick is off-centre or firebutton is down
  3130.             {   if (fire)                      // if firebutton is down
  3131.                 {   wormqueue(player, 0, 0);   // then shoot/jump
  3132.                 } else                         // if firebutton is up
  3133.                 {   wormqueue(player, xx, yy); // then move
  3134.         }   }   }
  3135.         OldPortState[port] = PortState[port];
  3136. }   }
  3137.  
  3138. EXPORT void flash(ULONG where)
  3139. {   TEXT saystring[SAYLIMIT + 1];
  3140.  
  3141.     stci_d(saystring, where);
  3142.     say(saystring, PURPLE);
  3143.     while(1);
  3144. }
  3145.  
  3146. EXPORT void ReadGamepads(void)
  3147. {   AUTO    ULONG PortState;
  3148.     AUTO    ABOOL fire = FALSE;
  3149.     AUTO    SBYTE i, xx = 0, yy = 0;
  3150.     PERSIST ULONG OldPortState = 0;
  3151.  
  3152.     for (i = 0; i <= 3; i++)
  3153.     {   if (worm[i].control == GAMEPAD && worm[i].lives)
  3154.         {   PortState = ReadJoyPort(worm[i].port);
  3155.             if (PortState != OldPortState)
  3156.             {   if (PortState & JP_BUTTON_MASK)
  3157.                 {   fire = TRUE;
  3158.                 }
  3159.                 if (PortState & JPF_JOY_UP)
  3160.                 {   yy = -1;
  3161.                 } elif (PortState & JPF_JOY_DOWN)
  3162.                 {   yy = 1;
  3163.                 }
  3164.                 if (PortState & JPF_JOY_LEFT)
  3165.                 {   xx = -1;
  3166.                 } elif (PortState & JPF_JOY_RIGHT)
  3167.                 {   xx = 1;
  3168.                 }
  3169.                 if (fire)                 // if firebutton is down
  3170.                 {   wormqueue(i, 0, 0);   // then shoot/jump
  3171.                 } elif (xx || yy)
  3172.                 {   wormqueue(i, xx, yy);
  3173.             }   }
  3174.             OldPortState = PortState;
  3175. }   }   }
  3176.  
  3177. EXPORT void whiteline(void)
  3178. {    SetAPen(MainWindowPtr->RPort, WHITE);
  3179. }
  3180. EXPORT void colourline(SBYTE player)
  3181. {    SetAPen(MainWindowPtr->RPort, worm[player].colour);
  3182. }
  3183.  
  3184. #ifdef __STORM__
  3185.  
  3186. EXPORT int stci_d(char* out, int lvalue)
  3187. {   return(stcl_d(out, lvalue));
  3188. }
  3189.  
  3190. EXPORT int stcl_d(char* out, long lvalue)
  3191. {   ULONG calc,
  3192.           i,
  3193.           where;
  3194.     FLAG  started = FALSE;
  3195.  
  3196.      if (lvalue < 0)
  3197.     {   out[0] = '-';
  3198.         where = 1;
  3199.         lvalue = abs(lvalue);
  3200.     } else
  3201.     {   where = 0;
  3202.     }
  3203.  
  3204.     for (i = ONE_BILLION; i >= 1; i /= 10)
  3205.     {   calc = lvalue / i;
  3206.         assert(calc < 10);
  3207.         if (calc || started || i == 1)
  3208.         {   *(out + where) = (char) ('0' + calc);
  3209.             where++;
  3210.             started = TRUE;
  3211.         }
  3212.         lvalue %= i;
  3213.     }
  3214.  
  3215.     *(out + where) = 0;
  3216.     return(where);
  3217. }
  3218.  
  3219. #endif
  3220.  
  3221. EXPORT void playsong(UBYTE whichsong)
  3222. {   if (song != whichsong)
  3223.     {   song = whichsong;
  3224.  
  3225.         if (mode == MUSIC && musicable)
  3226.         {   StopPlayer();
  3227.             PlayModule(SongPtr[song]);
  3228. }   }   }
  3229.